Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 74a5cad

Browse files
Restrict conda binary to be from PATH or Settings (#24709)
Closes #24627 --------- Co-authored-by: Eleanor Boyd <[email protected]>
1 parent 9bc9f68 commit 74a5cad

File tree

4 files changed

+56
-6
lines changed

4 files changed

+56
-6
lines changed

src/client/common/utils/platform.ts

+8
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,11 @@ export function getUserHomeDir(): string | undefined {
7171
export function isWindows(): boolean {
7272
return getOSType() === OSType.Windows;
7373
}
74+
75+
export function getPathEnvVariable(): string[] {
76+
const value = getEnvironmentVariable('PATH') || getEnvironmentVariable('Path');
77+
if (value) {
78+
return value.split(isWindows() ? ';' : ':');
79+
}
80+
return [];
81+
}

src/client/pythonEnvironments/common/environmentManagers/conda.ts

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { OUTPUT_MARKER_SCRIPT } from '../../../common/process/internal/scripts';
2424
import { splitLines } from '../../../common/stringUtils';
2525
import { SpawnOptions } from '../../../common/process/types';
2626
import { sleep } from '../../../common/utils/async';
27+
import { getConfiguration } from '../../../common/vscodeApis/workspaceApis';
2728

2829
export const AnacondaCompanyName = 'Anaconda, Inc.';
2930
export const CONDAPATH_SETTING_KEY = 'condaPath';
@@ -633,3 +634,8 @@ export async function getCondaEnvDirs(): Promise<string[] | undefined> {
633634
const conda = await Conda.getConda();
634635
return conda?.getEnvDirs();
635636
}
637+
638+
export function getCondaPathSetting(): string | undefined {
639+
const config = getConfiguration('python');
640+
return config.get<string>(CONDAPATH_SETTING_KEY, '');
641+
}

src/client/pythonEnvironments/nativeAPI.ts

+33-4
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ import {
2020
NativePythonFinder,
2121
} from './base/locators/common/nativePythonFinder';
2222
import { createDeferred, Deferred } from '../common/utils/async';
23-
import { Architecture, getUserHomeDir } from '../common/utils/platform';
23+
import { Architecture, getPathEnvVariable, getUserHomeDir } from '../common/utils/platform';
2424
import { parseVersion } from './base/info/pythonVersion';
2525
import { cache } from '../common/utils/decorators';
2626
import { traceError, traceInfo, traceLog, traceWarn } from '../logging';
2727
import { StopWatch } from '../common/utils/stopWatch';
2828
import { FileChangeType } from '../common/platform/fileSystemWatcher';
2929
import { categoryToKind, NativePythonEnvironmentKind } from './base/locators/common/nativePythonUtils';
30-
import { getCondaEnvDirs, setCondaBinary } from './common/environmentManagers/conda';
30+
import { getCondaEnvDirs, getCondaPathSetting, setCondaBinary } from './common/environmentManagers/conda';
3131
import { setPyEnvBinary } from './common/environmentManagers/pyenv';
3232
import {
3333
createPythonWatcher,
@@ -166,6 +166,12 @@ function isSubDir(pathToCheck: string | undefined, parents: string[]): boolean {
166166
});
167167
}
168168

169+
function foundOnPath(fsPath: string): boolean {
170+
const paths = getPathEnvVariable().map((p) => path.normalize(p).toLowerCase());
171+
const normalized = path.normalize(fsPath).toLowerCase();
172+
return paths.some((p) => normalized.includes(p));
173+
}
174+
169175
function getName(nativeEnv: NativeEnvInfo, kind: PythonEnvKind, condaEnvDirs: string[]): string {
170176
if (nativeEnv.name) {
171177
return nativeEnv.name;
@@ -387,13 +393,36 @@ class NativePythonEnvironments implements IDiscoveryAPI, Disposable {
387393
return undefined;
388394
}
389395

396+
private condaPathAlreadySet: string | undefined;
397+
390398
// eslint-disable-next-line class-methods-use-this
391399
private processEnvManager(native: NativeEnvManagerInfo) {
392400
const tool = native.tool.toLowerCase();
393401
switch (tool) {
394402
case 'conda':
395-
traceLog(`Conda environment manager found at: ${native.executable}`);
396-
setCondaBinary(native.executable);
403+
{
404+
traceLog(`Conda environment manager found at: ${native.executable}`);
405+
const settingPath = getCondaPathSetting();
406+
if (!this.condaPathAlreadySet) {
407+
if (settingPath === '' || settingPath === undefined) {
408+
if (foundOnPath(native.executable)) {
409+
setCondaBinary(native.executable);
410+
this.condaPathAlreadySet = native.executable;
411+
traceInfo(`Using conda: ${native.executable}`);
412+
} else {
413+
traceInfo(`Conda not found on PATH, skipping: ${native.executable}`);
414+
traceInfo(
415+
'You can set the path to conda using the setting: `python.condaPath` if you want to use a different conda binary',
416+
);
417+
}
418+
} else {
419+
traceInfo(`Using conda from setting: ${settingPath}`);
420+
this.condaPathAlreadySet = settingPath;
421+
}
422+
} else {
423+
traceInfo(`Conda set to: ${this.condaPathAlreadySet}`);
424+
}
425+
}
397426
break;
398427
case 'pyenv':
399428
traceLog(`Pyenv environment manager found at: ${native.executable}`);

src/test/pythonEnvironments/nativeAPI.unit.test.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
NativeEnvManagerInfo,
1414
NativePythonFinder,
1515
} from '../../client/pythonEnvironments/base/locators/common/nativePythonFinder';
16-
import { Architecture, isWindows } from '../../client/common/utils/platform';
16+
import { Architecture, getPathEnvVariable, isWindows } from '../../client/common/utils/platform';
1717
import { PythonEnvInfo, PythonEnvKind, PythonEnvType } from '../../client/pythonEnvironments/base/info';
1818
import { NativePythonEnvironmentKind } from '../../client/pythonEnvironments/base/locators/common/nativePythonUtils';
1919
import * as condaApi from '../../client/pythonEnvironments/common/environmentManagers/conda';
@@ -25,6 +25,8 @@ suite('Native Python API', () => {
2525
let api: IDiscoveryAPI;
2626
let mockFinder: typemoq.IMock<NativePythonFinder>;
2727
let setCondaBinaryStub: sinon.SinonStub;
28+
let getCondaPathSettingStub: sinon.SinonStub;
29+
let getCondaEnvDirsStub: sinon.SinonStub;
2830
let setPyEnvBinaryStub: sinon.SinonStub;
2931
let createPythonWatcherStub: sinon.SinonStub;
3032
let mockWatcher: typemoq.IMock<pw.PythonWatcher>;
@@ -136,6 +138,8 @@ suite('Native Python API', () => {
136138

137139
setup(() => {
138140
setCondaBinaryStub = sinon.stub(condaApi, 'setCondaBinary');
141+
getCondaEnvDirsStub = sinon.stub(condaApi, 'getCondaEnvDirs');
142+
getCondaPathSettingStub = sinon.stub(condaApi, 'getCondaPathSetting');
139143
setPyEnvBinaryStub = sinon.stub(pyenvApi, 'setPyEnvBinary');
140144
getWorkspaceFoldersStub = sinon.stub(ws, 'getWorkspaceFolders');
141145
getWorkspaceFoldersStub.returns([]);
@@ -294,9 +298,12 @@ suite('Native Python API', () => {
294298
});
295299

296300
test('Setting conda binary', async () => {
301+
getCondaPathSettingStub.returns(undefined);
302+
getCondaEnvDirsStub.resolves(undefined);
303+
const condaFakeDir = getPathEnvVariable()[0];
297304
const condaMgr: NativeEnvManagerInfo = {
298305
tool: 'Conda',
299-
executable: '/usr/bin/conda',
306+
executable: path.join(condaFakeDir, 'conda'),
300307
};
301308
mockFinder
302309
.setup((f) => f.refresh())

0 commit comments

Comments
 (0)