From fdddaf9899df729ddfafe085e2cde7218c3b74c5 Mon Sep 17 00:00:00 2001 From: Anthony Kim <62267334+anthonykim1@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:48:12 -0700 Subject: [PATCH] Additional graceful handling for pixi (#23942) In addition to first PR https://github.com/microsoft/vscode-python/pull/23937 I've been able to repro aggressive errors of ``` 2024-08-12 13:59:21.087 [error] [Error: spawn pixi ENOENT at ChildProcess._handle.onexit (node:internal/child_process:286:19) at onErrorNT (node:internal/child_process:484:16) at process.processTicksAndRejections (node:internal/process/task_queues:82:21)] { errno: -2, code: 'ENOENT', syscall: 'spawn pixi', path: 'pixi', spawnargs: [ '--version' ] } ``` ``` 2024-08-12 13:59:20.794 [error] Reading directory to watch failed [Error: ENOENT: no such file or directory, scandir '/Users/anthonykim/Desktop/vscode-python/.pixi/envs' at Object.readdirSync (node:fs:1509:26) at t.readdirSync (node:electron/js2c/node_init:2:11418) at /Users/anthonykim/.vscode/extensions/ms-python.python-2024.13.2024080901-darwin-arm64/out/client/extension.js:2:583006 at /Users/anthonykim/.vscode/extensions/ms-python.python-2024.13.2024080901-darwin-arm64/out/client/extension.js:2:583197 at Array.map () at d.initWatchers (/Users/anthonykim/.vscode/extensions/ms-python.python-2024.13.2024080901-darwin-arm64/out/client/extension.js:2:582915) at async d.ensureWatchersReady (/Users/anthonykim/.vscode/extensions/ms-python.python-2024.13.2024080901-darwin-arm64/out/client/extension.js:2:539326)] { errno: -2, code: 'ENOENT', syscall: 'scandir', path: '/Users/anthonykim/Desktop/vscode-python/.pixi/envs' } ``` even when I dont have pixi in my workspace. Changing the log level on this and adding more wraps around that should give necessary hint/message when needed without crashing program. --------- Co-authored-by: Karthik Nadig --- .../base/locators/common/resourceBasedLocator.ts | 8 ++++++-- .../base/locators/lowLevel/fsWatchingLocator.ts | 8 ++++---- .../common/environmentManagers/pixi.ts | 10 ++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/client/pythonEnvironments/base/locators/common/resourceBasedLocator.ts b/src/client/pythonEnvironments/base/locators/common/resourceBasedLocator.ts index 9391888cf0cf..8b56b4c7b8c1 100644 --- a/src/client/pythonEnvironments/base/locators/common/resourceBasedLocator.ts +++ b/src/client/pythonEnvironments/base/locators/common/resourceBasedLocator.ts @@ -4,7 +4,7 @@ import { IDisposable } from '../../../../common/types'; import { createDeferred, Deferred } from '../../../../common/utils/async'; import { Disposables } from '../../../../common/utils/resourceLifecycle'; -import { traceError } from '../../../../logging'; +import { traceError, traceWarn } from '../../../../logging'; import { arePathsSame, isVirtualWorkspace } from '../../../common/externalDependencies'; import { getEnvPath } from '../../info/env'; import { BasicEnvInfo, IPythonEnvsIterator, Locator, PythonLocatorQuery } from '../../locator'; @@ -36,7 +36,11 @@ export abstract class LazyResourceBasedLocator extends Locator imp protected async activate(): Promise { await this.ensureResourcesReady(); // There is not need to wait for the watchers to get started. - this.ensureWatchersReady().ignoreErrors(); + try { + this.ensureWatchersReady(); + } catch (ex) { + traceWarn(`Failed to ensure watchers are ready for locator ${this.constructor.name}`, ex); + } } public async dispose(): Promise { diff --git a/src/client/pythonEnvironments/base/locators/lowLevel/fsWatchingLocator.ts b/src/client/pythonEnvironments/base/locators/lowLevel/fsWatchingLocator.ts index 71bd30f7cfdc..dd7db5538565 100644 --- a/src/client/pythonEnvironments/base/locators/lowLevel/fsWatchingLocator.ts +++ b/src/client/pythonEnvironments/base/locators/lowLevel/fsWatchingLocator.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import { Uri } from 'vscode'; import { FileChangeType, watchLocationForPattern } from '../../../../common/platform/fileSystemWatcher'; import { sleep } from '../../../../common/utils/async'; -import { traceError, traceVerbose } from '../../../../logging'; +import { traceVerbose, traceWarn } from '../../../../logging'; import { getEnvironmentDirFromPath } from '../../../common/commonUtils'; import { PythonEnvStructure, @@ -32,13 +32,13 @@ function checkDirWatchable(dirname: string): DirUnwatchableReason { names = fs.readdirSync(dirname); } catch (err) { const exception = err as NodeJS.ErrnoException; - traceError('Reading directory to watch failed', exception); + traceVerbose('Reading directory failed', exception); if (exception.code === 'ENOENT') { // Treat a missing directory as unwatchable since it can lead to CPU load issues: // https://github.com/microsoft/vscode-python/issues/18459 return 'directory does not exist'; } - throw err; // re-throw + return undefined; } // The limit here is an educated guess. if (names.length > 200) { @@ -117,7 +117,7 @@ export abstract class FSWatchingLocator extends LazyResourceBasedLocator { // that might be watched due to a glob are not checked. const unwatchable = await checkDirWatchable(root); if (unwatchable) { - traceError(`Dir "${root}" is not watchable (${unwatchable})`); + traceWarn(`Dir "${root}" is not watchable (${unwatchable})`); return undefined; } return root; diff --git a/src/client/pythonEnvironments/common/environmentManagers/pixi.ts b/src/client/pythonEnvironments/common/environmentManagers/pixi.ts index 7aa1d55acd2c..d7baa4b53f6e 100644 --- a/src/client/pythonEnvironments/common/environmentManagers/pixi.ts +++ b/src/client/pythonEnvironments/common/environmentManagers/pixi.ts @@ -9,7 +9,7 @@ import { OSType, getOSType, getUserHomeDir } from '../../../common/utils/platfor import { exec, getPythonSetting, onDidChangePythonSetting, pathExists, pathExistsSync } from '../externalDependencies'; import { cache } from '../../../common/utils/decorators'; import { isTestExecution } from '../../../common/constants'; -import { traceError, traceVerbose, traceWarn } from '../../../logging'; +import { traceVerbose, traceWarn } from '../../../logging'; import { OUTPUT_MARKER_SCRIPT } from '../../../common/process/internal/scripts'; export const PIXITOOLPATH_SETTING_KEY = 'pixiToolPath'; @@ -119,7 +119,7 @@ export class Pixi { yield customPixiToolPath; } } catch (ex) { - traceError(`Failed to get pixi setting`, ex); + traceWarn(`Failed to get pixi setting`, ex); } // Check unqualified filename, in case it's on PATH. @@ -182,7 +182,7 @@ export class Pixi { const pixiInfo: PixiInfo = JSON.parse(infoOutput.stdout); return pixiInfo; } catch (error) { - traceError(`Failed to get pixi info for ${cwd}`, error); + traceWarn(`Failed to get pixi info for ${cwd}`, error); return undefined; } } @@ -199,15 +199,13 @@ export class Pixi { if (!versionOutput || !versionOutput.stdout) { return undefined; } - const versionParts = versionOutput.stdout.split(' '); if (versionParts.length < 2) { return undefined; } - return versionParts[1].trim(); } catch (error) { - traceError(`Failed to get pixi version`, error); + traceVerbose(`Failed to get pixi version`, error); return undefined; } }