Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Activate environment in terminal #614

Merged
merged 86 commits into from
Jan 23, 2018
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
ecc1ca9
Fix Microsoft/vscode#37627 (#1368)
octref Nov 3, 2017
7c5778c
Version 0.7.0 of extension (#1381)
DonJayamanne Nov 9, 2017
9d1bf82
Update README.md
DonJayamanne Nov 9, 2017
ffba179
Update README.md
DonJayamanne Nov 9, 2017
905c713
sync fork with upstream
DonJayamanne Nov 10, 2017
acc2109
fix readme
DonJayamanne Nov 10, 2017
d470523
Merge branch 'master' of https://github.com/Microsoft/vscode-python
DonJayamanne Nov 16, 2017
d392e8b
merged upstream
DonJayamanne Nov 16, 2017
92f775f
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 20, 2017
32a6e53
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 21, 2017
4b30f2c
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 22, 2017
e396752
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 22, 2017
eff4792
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 28, 2017
4553c28
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 28, 2017
3c6520a
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 28, 2017
966e516
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 28, 2017
63d2d65
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 28, 2017
f6d469e
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 28, 2017
029e055
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 30, 2017
e8c71c0
Merge remote-tracking branch 'upstream/master'
DonJayamanne Nov 30, 2017
51cf9d2
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 1, 2017
7aadc43
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 1, 2017
f0f5c59
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 4, 2017
b2b9da9
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 4, 2017
30a4091
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 5, 2017
b16d2f9
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 6, 2017
c8db345
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 7, 2017
0df7f16
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 8, 2017
3ccc881
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 9, 2017
bb0709e
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 11, 2017
2c19004
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 11, 2017
8f224ab
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 11, 2017
41b7080
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 12, 2017
dab38dc
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 12, 2017
ae22dd4
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 12, 2017
d2340d2
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 14, 2017
52bb7ae
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 15, 2017
b6b2531
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 19, 2017
8d8d2fc
Merge remote-tracking branch 'upstream/master'
DonJayamanne Dec 19, 2017
c425a55
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 3, 2018
3963217
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 3, 2018
a696f2a
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 3, 2018
a31e659
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 4, 2018
2663cd5
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 4, 2018
7c85e0b
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 5, 2018
beb82c2
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 9, 2018
01e722a
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 10, 2018
06cf61c
first set
DonJayamanne Jan 11, 2018
83148c1
tests for terminal services
DonJayamanne Jan 12, 2018
b336bd1
remove unsed var
DonJayamanne Jan 12, 2018
5489575
refactor execution of code in terminals
DonJayamanne Jan 16, 2018
7de62aa
revert change to tests grep
DonJayamanne Jan 16, 2018
36d2aa5
removed duplicate type definition
DonJayamanne Jan 16, 2018
686aca9
ensure title is set
DonJayamanne Jan 16, 2018
ddc46c9
revert retry count
DonJayamanne Jan 16, 2018
4571e48
account for PYTHONPATH in current test environment (existing machine)
DonJayamanne Jan 17, 2018
d84da8e
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 17, 2018
c8b7185
terminal service can only be created through factory
DonJayamanne Jan 17, 2018
5c6e50c
add method to get active interpeter info
DonJayamanne Jan 18, 2018
78da3e1
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 19, 2018
efba660
refactor conda service
DonJayamanne Jan 19, 2018
8d67246
fix tests
DonJayamanne Jan 19, 2018
d9a23fd
incremental
DonJayamanne Jan 21, 2018
b735c7e
added activation scripts
DonJayamanne Jan 22, 2018
2262a6f
merged
DonJayamanne Jan 22, 2018
2ebe2e6
fix terminal tests
DonJayamanne Jan 22, 2018
0b71c44
fix linter error
DonJayamanne Jan 22, 2018
fc8d5b5
revert changes
DonJayamanne Jan 22, 2018
9593d24
refactor REPL provider to use new terminal services
DonJayamanne Jan 22, 2018
fdc03e5
refactor activation commands
DonJayamanne Jan 23, 2018
7d82c77
revert change
DonJayamanne Jan 23, 2018
685b683
Merge remote-tracking branch 'upstream/master'
DonJayamanne Jan 23, 2018
c165901
merged master
DonJayamanne Jan 23, 2018
fb6142a
fix detection of conda tests
DonJayamanne Jan 23, 2018
0ff33e9
tests for bash,cshell and fish activation scripts
DonJayamanne Jan 23, 2018
7ba90db
better test suite names
DonJayamanne Jan 23, 2018
faf48b5
added more tests
DonJayamanne Jan 23, 2018
605fabe
added tests for env activation
DonJayamanne Jan 23, 2018
96a4571
added tests for activation commands
DonJayamanne Jan 23, 2018
a8b4e7c
fix linter errors
DonJayamanne Jan 23, 2018
001fc30
unit tests for repl provider
DonJayamanne Jan 23, 2018
b9d503b
fix code review comments
DonJayamanne Jan 23, 2018
264e52a
extension method to quote strings for cmd args
DonJayamanne Jan 23, 2018
3e7c1aa
give preference to scripts based on shell
DonJayamanne Jan 23, 2018
2985dad
fix types of script files supported by shells
DonJayamanne Jan 23, 2018
8bf8a17
activate terminal before displaying it
DonJayamanne Jan 23, 2018
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
22 changes: 21 additions & 1 deletion src/client/common/application/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// tslint:disable:no-any unified-signatures

import * as vscode from 'vscode';
import { CancellationToken, Disposable, Event, FileSystemWatcher, GlobPattern, TextDocument, TextDocumentShowOptions } from 'vscode';
import { CancellationToken, Disposable, Event, FileSystemWatcher, GlobPattern, TextDocument, TextDocumentShowOptions, WorkspaceConfiguration } from 'vscode';
import { TextEditor, TextEditorEdit, TextEditorOptionsChangeEvent, TextEditorSelectionChangeEvent, TextEditorViewColumnChangeEvent } from 'vscode';
import { Uri, ViewColumn, WorkspaceFolder, WorkspaceFoldersChangeEvent } from 'vscode';
import { Terminal, TerminalOptions } from 'vscode';
Expand Down Expand Up @@ -363,6 +363,11 @@ export interface IWorkspaceService {
*/
readonly onDidChangeWorkspaceFolders: Event<WorkspaceFoldersChangeEvent>;

/**
* An event that is emitted when the [configuration](#WorkspaceConfiguration) changed.
*/
readonly onDidChangeConfiguration: Event<void>;

/**
* Returns the [workspace folder](#WorkspaceFolder) that contains a given uri.
* * returns `undefined` when the given uri doesn't match any workspace folder
Expand Down Expand Up @@ -419,6 +424,21 @@ export interface IWorkspaceService {
* [workspace folders](#workspace.workspaceFolders) are opened.
*/
findFiles(include: GlobPattern, exclude?: GlobPattern, maxResults?: number, token?: CancellationToken): Thenable<Uri[]>;

/**
* Get a workspace configuration object.
*
* When a section-identifier is provided only that part of the configuration
* is returned. Dots in the section-identifier are interpreted as child-access,
* like `{ myExt: { setting: { doIt: true }}}` and `getConfiguration('myExt.setting').get('doIt') === true`.
*
* When a resource is provided, configuration scoped to that resource is returned.
*
* @param section A dot-separated identifier.
* @param resource A resource for which the configuration is asked for
* @return The full configuration or a subset.
*/
getConfiguration(section?: string, resource?: Uri): WorkspaceConfiguration;
}

export const ITerminalManager = Symbol('ITerminalManager');
Expand Down
8 changes: 7 additions & 1 deletion src/client/common/application/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
// Licensed under the MIT License.

import { injectable } from 'inversify';
import { CancellationToken, Event, FileSystemWatcher, GlobPattern, Uri, workspace, WorkspaceFolder, WorkspaceFoldersChangeEvent } from 'vscode';
import { CancellationToken, Event, FileSystemWatcher, GlobPattern, Uri, workspace, WorkspaceConfiguration, WorkspaceFolder, WorkspaceFoldersChangeEvent } from 'vscode';
import { IWorkspaceService } from './types';

@injectable()
export class WorkspaceService implements IWorkspaceService {
public get onDidChangeConfiguration(): Event<void> {
return workspace.onDidChangeConfiguration;
}
public get rootPath(): string | undefined {
return workspace.rootPath;
}
Expand All @@ -16,6 +19,9 @@ export class WorkspaceService implements IWorkspaceService {
public get onDidChangeWorkspaceFolders(): Event<WorkspaceFoldersChangeEvent> {
return workspace.onDidChangeWorkspaceFolders;
}
public getConfiguration(section?: string, resource?: Uri): WorkspaceConfiguration {
return workspace.getConfiguration(section, resource);
}
public getWorkspaceFolder(uri: Uri): WorkspaceFolder | undefined {
return workspace.getWorkspaceFolder(uri);
}
Expand Down
54 changes: 11 additions & 43 deletions src/client/common/installer/condaInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@
// Licensed under the MIT License.

import { inject, injectable } from 'inversify';
import * as path from 'path';
import { Uri } from 'vscode';
import { ICondaLocatorService, IInterpreterLocatorService, INTERPRETER_LOCATOR_SERVICE, InterpreterType } from '../../interpreter/contracts';
import { CONDA_RELATIVE_PY_PATH } from '../../interpreter/locators/services/conda';
import { ICondaService, IInterpreterService, InterpreterType } from '../../interpreter/contracts';
import { IServiceContainer } from '../../ioc/types';
import { PythonSettings } from '../configSettings';
import { IPythonExecutionFactory } from '../process/types';
import { ExecutionInfo } from '../types';
import { arePathsSame } from '../utils';
import { ModuleInstaller } from './moduleInstaller';
import { IModuleInstaller } from './types';

Expand All @@ -35,7 +30,7 @@ export class CondaInstaller extends ModuleInstaller implements IModuleInstaller
if (typeof this.isCondaAvailable === 'boolean') {
return this.isCondaAvailable!;
}
const condaLocator = this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const condaLocator = this.serviceContainer.get<ICondaService>(ICondaService);
const available = await condaLocator.isCondaAvailable();

if (!available) {
Expand All @@ -46,20 +41,21 @@ export class CondaInstaller extends ModuleInstaller implements IModuleInstaller
return this.isCurrentEnvironmentACondaEnvironment(resource);
}
protected async getExecutionInfo(moduleName: string, resource?: Uri): Promise<ExecutionInfo> {
const condaLocator = this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const condaLocator = this.serviceContainer.get<ICondaService>(ICondaService);
const condaFile = await condaLocator.getCondaFile();

const info = await this.getCurrentInterpreterInfo(resource);
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
const info = await interpreterService.getActiveInterpreter(resource);
const args = ['install'];

if (info.envName) {
if (info!.envName) {
// If we have the name of the conda environment, then use that.
args.push('--name');
args.push(info.envName!);
args.push(info!.envName!);
} else {
// Else provide the full path to the environment path.
args.push('--prefix');
args.push(info.envPath);
args.push(info!.envPath!);
}
args.push(moduleName);
return {
Expand All @@ -68,37 +64,9 @@ export class CondaInstaller extends ModuleInstaller implements IModuleInstaller
moduleName: ''
};
}
private async getCurrentPythonPath(resource?: Uri): Promise<string> {
const pythonPath = PythonSettings.getInstance(resource).pythonPath;
if (path.basename(pythonPath) === pythonPath) {
const pythonProc = await this.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory).create(resource);
return pythonProc.getExecutablePath().catch(() => pythonPath);
} else {
return pythonPath;
}
}
private isCurrentEnvironmentACondaEnvironment(resource?: Uri) {
return this.getCurrentInterpreterInfo(resource)
.then(info => info && info.isConda === true).catch(() => false);
}
private async getCurrentInterpreterInfo(resource?: Uri) {
// Use this service, though it returns everything it is cached.
const interpreterLocator = this.serviceContainer.get<IInterpreterLocatorService>(IInterpreterLocatorService, INTERPRETER_LOCATOR_SERVICE);
const interpretersPromise = interpreterLocator.getInterpreters(resource);
const pythonPathPromise = this.getCurrentPythonPath(resource);
const [interpreters, currentPythonPath] = await Promise.all([interpretersPromise, pythonPathPromise]);

// Check if we have the info about the current python path.
const pathToCompareWith = path.dirname(currentPythonPath);
const info = interpreters.find(item => arePathsSame(path.dirname(item.path), pathToCompareWith));
// tslint:disable-next-line:prefer-array-literal
const pathsToRemove = new Array(CONDA_RELATIVE_PY_PATH.length).fill('..') as string[];
const envPath = path.join(path.dirname(currentPythonPath), ...pathsToRemove);
return {
isConda: info && info!.type === InterpreterType.Conda,
pythonPath: currentPythonPath,
envPath,
envName: info ? info!.envName : undefined
};
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
return interpreterService.getActiveInterpreter(resource)
.then(info => info ? info.type === InterpreterType.Conda : false).catch(() => false);
}
}
7 changes: 4 additions & 3 deletions src/client/common/installer/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { PythonSettings } from '../configSettings';
import { STANDARD_OUTPUT_CHANNEL } from '../constants';
import { IPlatformService } from '../platform/types';
import { IProcessService, IPythonExecutionFactory } from '../process/types';
import { ITerminalService } from '../terminal/types';
import { IInstaller, ILogger, InstallerResponse, IOutputChannel, IsWindows, ModuleNamePurpose, Product } from '../types';
import { ITerminalServiceFactory } from '../terminal/types';
import { IInstaller, ILogger, InstallerResponse, IOutputChannel, ModuleNamePurpose, Product } from '../types';
import { IModuleInstaller } from './types';

export { Product } from '../types';
Expand Down Expand Up @@ -237,7 +237,8 @@ export class Installer implements IInstaller {
this.outputChannel.appendLine('Option 3: Extract to any folder and define that path in the python.workspaceSymbols.ctagsPath setting of your user settings file (settings.json).');
this.outputChannel.show();
} else {
const terminalService = this.serviceContainer.get<ITerminalService>(ITerminalService);
const terminalServiceFactory = this.serviceContainer.get<ITerminalServiceFactory>(ITerminalServiceFactory);
const terminalService = terminalServiceFactory.getTerminalService();
const logger = this.serviceContainer.get<ILogger>(ILogger);
terminalService.sendCommand(CTagsInsllationScript, [])
.catch(logger.logError.bind(logger, `Failed to install ctags. Script sent '${CTagsInsllationScript}'.`));
Expand Down
4 changes: 2 additions & 2 deletions src/client/common/installer/moduleInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import { IServiceContainer } from '../../ioc/types';
import { PythonSettings } from '../configSettings';
import { STANDARD_OUTPUT_CHANNEL } from '../constants';
import { IFileSystem } from '../platform/types';
import { ITerminalService } from '../terminal/types';
import { ITerminalServiceFactory } from '../terminal/types';
import { ExecutionInfo, IOutputChannel } from '../types';

@injectable()
export abstract class ModuleInstaller {
constructor(protected serviceContainer: IServiceContainer) { }
public async installModule(name: string, resource?: vscode.Uri): Promise<void> {
const executionInfo = await this.getExecutionInfo(name, resource);
const terminalService = this.serviceContainer.get<ITerminalService>(ITerminalService);
const terminalService = this.serviceContainer.get<ITerminalServiceFactory>(ITerminalServiceFactory).getTerminalService();

if (executionInfo.moduleName) {
const settings = PythonSettings.getInstance(resource);
Expand Down
21 changes: 14 additions & 7 deletions src/client/common/platform/fileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,22 @@
// Licensed under the MIT License.
'use strict';

import * as fs from 'fs';
import * as fse from 'fs-extra';
import * as fs from 'fs-extra';
import { inject, injectable } from 'inversify';
import * as path from 'path';
import { IServiceContainer } from '../../ioc/types';
import { IFileSystem, IPlatformService } from './types';

@injectable()
export class FileSystem implements IFileSystem {
constructor( @inject(IServiceContainer) private platformService: IPlatformService) { }
constructor( @inject(IPlatformService) private platformService: IPlatformService) { }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you, there is always a discussion if one should pass container or just minimal service(s). However, if we are to switch to our own container implementation, it may not be injectable so we'll have to pass around container anyway.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, just didn't want to change existing code.
The plan going forward is to only pass the service container


public get directorySeparatorChar(): string {
return path.sep;
}

public objectExistsAsync(filePath: string, statCheck: (s: fs.Stats) => boolean): Promise<boolean> {
return new Promise<boolean>(resolve => {
fse.stat(filePath, (error, stats) => {
fs.stat(filePath, (error, stats) => {
if (error) {
return resolve(false);
}
Expand All @@ -31,13 +29,22 @@ export class FileSystem implements IFileSystem {
public fileExistsAsync(filePath: string): Promise<boolean> {
return this.objectExistsAsync(filePath, (stats) => stats.isFile());
}
/**
* Reads the contents of the file using utf8 and returns the string contents.
* @param {string} filePath
* @returns {Promise<string>}
* @memberof FileSystem
*/
public readFile(filePath: string): Promise<string> {
return fs.readFile(filePath).then(buffer => buffer.toString());
}

public directoryExistsAsync(filePath: string): Promise<boolean> {
return this.objectExistsAsync(filePath, (stats) => stats.isDirectory());
}

public createDirectoryAsync(directoryPath: string): Promise<void> {
return fse.mkdirp(directoryPath);
return fs.mkdirp(directoryPath);
}

public getSubDirectoriesAsync(rootDir: string): Promise<string[]> {
Expand All @@ -46,7 +53,7 @@ export class FileSystem implements IFileSystem {
if (error) {
return resolve([]);
}
const subDirs = [];
const subDirs: string[] = [];
files.forEach(name => {
const fullPath = path.join(rootDir, name);
try {
Expand Down
1 change: 1 addition & 0 deletions src/client/common/platform/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ export interface IFileSystem {
createDirectoryAsync(path: string): Promise<void>;
getSubDirectoriesAsync(rootDir: string): Promise<string[]>;
arePathsSame(path1: string, path2: string): boolean;
readFile(filePath: string): Promise<string>;
}
11 changes: 7 additions & 4 deletions src/client/common/serviceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import { PersistentStateFactory } from './persistentState';
import { IS_64_BIT, IS_WINDOWS } from './platform/constants';
import { PathUtils } from './platform/pathUtils';
import { CurrentProcess } from './process/currentProcess';
import { Bash } from './terminal/environmentActivationProviders/bash';
import { CommandPromptAndPowerShell } from './terminal/environmentActivationProviders/commandPrompt';
import { TerminalServiceFactory } from './terminal/factory';
import { TerminalHelper } from './terminal/helper';
import { TerminalService } from './terminal/service';
import { ITerminalHelper, ITerminalService, ITerminalServiceFactory } from './terminal/types';
import { ITerminalActivationCommandProvider, ITerminalHelper, ITerminalServiceFactory } from './terminal/types';
import { IConfigurationService, ICurrentProcess, IInstaller, ILogger, IPathUtils, IPersistentStateFactory, Is64Bit, IsWindows } from './types';

export function registerTypes(serviceManager: IServiceManager) {
Expand All @@ -27,9 +28,7 @@ export function registerTypes(serviceManager: IServiceManager) {

serviceManager.addSingleton<IPersistentStateFactory>(IPersistentStateFactory, PersistentStateFactory);
serviceManager.addSingleton<ILogger>(ILogger, Logger);
serviceManager.addSingleton<ITerminalService>(ITerminalService, TerminalService);
serviceManager.addSingleton<ITerminalServiceFactory>(ITerminalServiceFactory, TerminalServiceFactory);
serviceManager.addSingleton<ITerminalHelper>(ITerminalHelper, TerminalHelper);
serviceManager.addSingleton<IPathUtils>(IPathUtils, PathUtils);
serviceManager.addSingleton<IApplicationShell>(IApplicationShell, ApplicationShell);
serviceManager.addSingleton<ICurrentProcess>(ICurrentProcess, CurrentProcess);
Expand All @@ -39,4 +38,8 @@ export function registerTypes(serviceManager: IServiceManager) {
serviceManager.addSingleton<IWorkspaceService>(IWorkspaceService, WorkspaceService);
serviceManager.addSingleton<IDocumentManager>(IDocumentManager, DocumentManager);
serviceManager.addSingleton<ITerminalManager>(ITerminalManager, TerminalManager);

serviceManager.addSingleton<ITerminalHelper>(ITerminalHelper, TerminalHelper);
serviceManager.addSingleton<ITerminalActivationCommandProvider>(ITerminalActivationCommandProvider, Bash, 'bashCShellFish');
serviceManager.addSingleton<ITerminalActivationCommandProvider>(ITerminalActivationCommandProvider, CommandPromptAndPowerShell, 'commandPromptAndPowerShell');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { injectable } from 'inversify';
import * as path from 'path';
import { PythonInterpreter } from '../../../interpreter/contracts';
import { IServiceContainer } from '../../../ioc/types';
import { IFileSystem } from '../../platform/types';
import { TerminalShellType } from '../types';
import { ITerminalActivationCommandProvider } from '../types';

@injectable()
export abstract class BaseActivationCommandProvider implements ITerminalActivationCommandProvider {
constructor(protected readonly serviceContainer: IServiceContainer) { }

public abstract isShellSupported(targetShell: TerminalShellType): boolean;
public abstract getActivationCommands(interpreter: PythonInterpreter, targetShell: TerminalShellType): Promise<string | string[] | undefined>;

protected async findScriptFile(interpreter: PythonInterpreter, scriptFileNames: string[]): Promise<string | undefined> {
const fs = this.serviceContainer.get<IFileSystem>(IFileSystem);

for (const scriptFileName of scriptFileNames) {
// Generate scripts are found in the same directory as the interpreter.
const scriptFile = path.join(path.dirname(interpreter.path), scriptFileName);
const found = await fs.fileExistsAsync(scriptFile);
if (found) {
return scriptFile;
}
}
}
}
31 changes: 31 additions & 0 deletions src/client/common/terminal/environmentActivationProviders/bash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { inject, injectable } from 'inversify';
import { PythonInterpreter } from '../../../interpreter/contracts';
import { IServiceContainer } from '../../../ioc/types';
import { TerminalShellType } from '../types';
import { BaseActivationCommandProvider } from './baseActivationProvider';

@injectable()
export class Bash extends BaseActivationCommandProvider {
constructor( @inject(IServiceContainer) serviceContainer: IServiceContainer) {
super(serviceContainer);
}
public isShellSupported(targetShell: TerminalShellType): boolean {
return targetShell === TerminalShellType.bash ||
targetShell === TerminalShellType.cshell ||
targetShell === TerminalShellType.fish;
}
public async getActivationCommands(interpreter: PythonInterpreter, targetShell: TerminalShellType): Promise<string | string[] | undefined> {
const scriptFile = await this.findScriptFile(interpreter, ['activate', 'activate.sh', 'activate.csh', 'activate.fish']);
if (!scriptFile) {
return;
}
const quotedScriptFile = scriptFile.indexOf(' ') > 0 ? `"${scriptFile}"` : scriptFile;
const envName = interpreter.envName ? interpreter.envName! : '';
// In the case of conda environments, the name of the environment must be provided.
// E.g. `source acrtivate <envname>`.
return `source ${quotedScriptFile} ${envName}`.trim();
}
}
Loading