Skip to content

Commit a7abeb6

Browse files
author
Kartik Raj
authored
Execute conda related commands using shell (#18767)
* Execute conda related commands using shell * Fix resolve utils unit tests * Oops
1 parent 5db5d7b commit a7abeb6

3 files changed

Lines changed: 14 additions & 8 deletions

File tree

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { lt, parse, SemVer } from 'semver';
44
import { getEnvironmentVariable, getOSType, getUserHomeDir, OSType } from '../../../common/utils/platform';
55
import {
66
arePathsSame,
7-
exec,
87
getPythonSetting,
98
isParentPath,
109
pathExists,
@@ -390,7 +389,9 @@ export class Conda {
390389
@cache(30_000, true, 10_000)
391390
// eslint-disable-next-line class-methods-use-this
392391
private async getInfoCached(command: string): Promise<CondaInfo> {
393-
const result = await exec(command, ['info', '--json'], { timeout: CONDA_GENERAL_TIMEOUT });
392+
const quoted = [command.toCommandArgument(), 'info', '--json'].join(' ');
393+
// Execute in a shell as `conda` on windows refers to `conda.bat`, which requires a shell to work.
394+
const result = await shellExecute(quoted, { timeout: CONDA_GENERAL_TIMEOUT });
394395
traceVerbose(`conda info --json: ${result.stdout}`);
395396
return JSON.parse(result.stdout);
396397
}
@@ -491,7 +492,9 @@ export class Conda {
491492
if (info && info.conda_version) {
492493
versionString = info.conda_version;
493494
} else {
494-
const stdOut = await exec(this.command, ['--version'], { timeout: CONDA_GENERAL_TIMEOUT })
495+
const quoted = `${this.command.toCommandArgument()} --version`;
496+
// Execute in a shell as `conda` on windows refers to `conda.bat`, which requires a shell to work.
497+
const stdOut = await shellExecute(quoted, { timeout: CONDA_GENERAL_TIMEOUT })
495498
.then((result) => result.stdout.trim())
496499
.catch<string | undefined>(() => undefined);
497500

src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ suite('Resolver Utils', () => {
247247

248248
test('resolveEnv (Windows)', async () => {
249249
sinon.stub(platformApis, 'getOSType').callsFake(() => platformApis.OSType.Windows);
250-
sinon.stub(externalDependencies, 'exec').callsFake(async (command: string, args: string[]) => {
250+
sinon.stub(externalDependencies, 'shellExecute').callsFake(async (quoted: string) => {
251+
const [command, ...args] = quoted.split(' ');
251252
if (command === 'conda' && args[0] === 'info' && args[1] === '--json') {
252253
return { stdout: JSON.stringify(condaInfo(condaPrefixWindows)) };
253254
}
@@ -262,7 +263,8 @@ suite('Resolver Utils', () => {
262263

263264
test('resolveEnv (non-Windows)', async () => {
264265
sinon.stub(platformApis, 'getOSType').callsFake(() => platformApis.OSType.Linux);
265-
sinon.stub(externalDependencies, 'exec').callsFake(async (command: string, args: string[]) => {
266+
sinon.stub(externalDependencies, 'shellExecute').callsFake(async (quoted: string) => {
267+
const [command, ...args] = quoted.split(' ');
266268
if (command === 'conda' && args[0] === 'info' && args[1] === '--json') {
267269
return { stdout: JSON.stringify(condaInfo(condaPrefixNonWindows)) };
268270
}
@@ -280,7 +282,7 @@ suite('Resolver Utils', () => {
280282

281283
test('resolveEnv: If no conda binary found, resolve as a simple environment', async () => {
282284
sinon.stub(platformApis, 'getOSType').callsFake(() => platformApis.OSType.Windows);
283-
sinon.stub(externalDependencies, 'exec').callsFake(async (command: string) => {
285+
sinon.stub(externalDependencies, 'shellExecute').callsFake(async (command: string) => {
284286
throw new Error(`${command} is missing or is not executable`);
285287
});
286288
const actual = await resolveBasicEnv({
@@ -603,7 +605,7 @@ suite('Resolver Utils', () => {
603605
});
604606

605607
test('If data provided by registry is less informative than kind resolvers, do not use it to update environment', async () => {
606-
sinon.stub(externalDependencies, 'exec').callsFake(async (command: string) => {
608+
sinon.stub(externalDependencies, 'shellExecute').callsFake(async (command: string) => {
607609
throw new Error(`${command} is missing or is not executable`);
608610
});
609611
const interpreterPath = path.join(regTestRoot, 'conda3', 'python.exe');

src/test/pythonEnvironments/common/environmentManagers/conda.unit.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ suite('Conda and its environments are located correctly', () => {
185185
return contents;
186186
});
187187

188-
sinon.stub(externalDependencies, 'exec').callsFake(async (command: string, args: string[]) => {
188+
sinon.stub(externalDependencies, 'shellExecute').callsFake(async (quoted: string) => {
189+
const [command, ...args] = quoted.split(' ');
189190
for (const prefix of ['', ...execPath]) {
190191
const contents = getFile(path.join(prefix, command));
191192
if (args[0] === 'info' && args[1] === '--json') {

0 commit comments

Comments
 (0)