Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/client/common/installer/condaInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export class CondaInstaller extends ModuleInstaller {
return {
args,
execPath: condaFile,
// Execute in a shell as `conda` on windows refers to `conda.bat`, which requires a shell to work.
useShell: true,
};
}

Expand Down
40 changes: 36 additions & 4 deletions src/client/common/installer/moduleInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,38 @@ export abstract class ModuleInstaller implements IModuleInstaller {
const pythonPath = isResource(resource) ? interpreterPath : resource.path;
const args = internalPython.execModule(executionInfo.moduleName, executionInfoArgs);
if (!interpreter || interpreter.envType !== EnvironmentType.Unknown) {
await this.executeCommand(shouldExecuteInTerminal, resource, pythonPath, args, token);
await this.executeCommand(
shouldExecuteInTerminal,
resource,
pythonPath,
args,
token,
executionInfo.useShell,
);
} else if (settings.globalModuleInstallation) {
const fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
if (await fs.isDirReadonly(path.dirname(pythonPath)).catch((_err) => true)) {
this.elevatedInstall(pythonPath, args);
} else {
await this.executeCommand(shouldExecuteInTerminal, resource, pythonPath, args, token);
await this.executeCommand(
shouldExecuteInTerminal,
resource,
pythonPath,
args,
token,
executionInfo.useShell,
);
}
} else if (name === translateProductToModule(Product.pip)) {
// Pip should always be installed into the specified environment.
await this.executeCommand(shouldExecuteInTerminal, resource, pythonPath, args, token);
await this.executeCommand(
shouldExecuteInTerminal,
resource,
pythonPath,
args,
token,
executionInfo.useShell,
);
} else {
await this.executeCommand(
shouldExecuteInTerminal,
Expand Down Expand Up @@ -173,6 +194,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
command: string,
args: string[],
token?: CancellationToken,
useShell?: boolean,
) {
const options: TerminalCreationOptions = {};
if (isResource(resource)) {
Expand All @@ -189,7 +211,17 @@ export abstract class ModuleInstaller implements IModuleInstaller {
} else {
const processServiceFactory = this.serviceContainer.get<IProcessServiceFactory>(IProcessServiceFactory);
const processService = await processServiceFactory.create(options.resource);
await processService.exec(command, args);
if (useShell) {
const argv = [command, ...args];
// Concat these together to make a set of quoted strings
const quoted = argv.reduce(
(p, c) => (p ? `${p} ${c.toCommandArgument()}` : `${c.toCommandArgument()}`),
'',
);
await processService.shellExec(quoted);
} else {
await processService.exec(command, args);
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/client/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export type ExecutionInfo = {
moduleName?: string;
args: string[];
product?: Product;
useShell?: boolean;
};

export enum InstallerResponse {
Expand Down
7 changes: 6 additions & 1 deletion src/test/common/installer/condaInstaller.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ suite('Common - Conda Installer', () => {

const execInfo = await installer.getExecutionInfo('abc', uri);

assert.deepEqual(execInfo, { args: ['install', '--name', condaEnv.name, 'abc', '-y'], execPath: condaPath });
assert.deepEqual(execInfo, {
args: ['install', '--name', condaEnv.name, 'abc', '-y'],
execPath: condaPath,
useShell: true,
});
});
test('Include path of environment', async () => {
const uri = Uri.file(__filename);
Expand All @@ -126,6 +130,7 @@ suite('Common - Conda Installer', () => {
assert.deepEqual(execInfo, {
args: ['install', '--prefix', condaEnv.path.fileToCommandArgument(), 'abc', '-y'],
execPath: condaPath,
useShell: true,
});
});
});