Skip to content

Commit

Permalink
First batch of changes
Browse files Browse the repository at this point in the history
  • Loading branch information
DonJayamanne committed Dec 27, 2018
1 parent ece8afd commit 2bc224e
Show file tree
Hide file tree
Showing 28 changed files with 654 additions and 161 deletions.
24 changes: 16 additions & 8 deletions src/client/common/configSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ConfigurationTarget, DiagnosticSeverity, Disposable, Uri,
workspace, WorkspaceConfiguration
} from 'vscode';
import { IInterpreterAutoSeletionProxyService } from '../interpreter/interpreterSelection/types';
import { sendTelemetryEvent } from '../telemetry';
import { COMPLETION_ADD_BRACKETS, FORMAT_ON_TYPE } from '../telemetry/constants';
import { isTestExecution } from './constants';
Expand Down Expand Up @@ -58,18 +59,18 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
// tslint:disable-next-line:variable-name
private _pythonPath = '';

constructor(workspaceFolder?: Uri) {
constructor(workspaceFolder: Uri | undefined, private readonly interpreterAutoSeletionService: IInterpreterAutoSeletionProxyService) {
super();
this.workspaceRoot = workspaceFolder ? workspaceFolder : Uri.file(__dirname);
this.initialize();
}
// tslint:disable-next-line:function-name
public static getInstance(resource?: Uri): PythonSettings {
public static getInstance(resource: Uri | undefined, interpreterAutoSeletionService: IInterpreterAutoSeletionProxyService): PythonSettings {
const workspaceFolderUri = PythonSettings.getSettingsUriAndTarget(resource).uri;
const workspaceFolderKey = workspaceFolderUri ? workspaceFolderUri.fsPath : '';

if (!PythonSettings.pythonSettings.has(workspaceFolderKey)) {
const settings = new PythonSettings(workspaceFolderUri);
const settings = new PythonSettings(workspaceFolderUri, interpreterAutoSeletionService);
PythonSettings.pythonSettings.set(workspaceFolderKey, settings);
const config = workspace.getConfiguration('editor', resource ? resource : null);
const formatOnType = config ? config.get('formatOnType', false) : false;
Expand Down Expand Up @@ -108,12 +109,17 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
this.disposables = [];
}
// tslint:disable-next-line:cyclomatic-complexity max-func-body-length
public update(pythonSettings: WorkspaceConfiguration) {
protected update(pythonSettings: WorkspaceConfiguration) {
const workspaceRoot = this.workspaceRoot.fsPath;
const systemVariables: SystemVariables = new SystemVariables(this.workspaceRoot ? this.workspaceRoot.fsPath : undefined);

// tslint:disable-next-line:no-backbone-get-set-outside-model no-non-null-assertion
this.pythonPath = systemVariables.resolveAny(pythonSettings.get<string>('pythonPath'))!;
const autoSelectedPythonPath = this.interpreterAutoSeletionService.getAutoSelectedInterpreter(this.workspaceRoot);
if (autoSelectedPythonPath) {
this.pythonPath = autoSelectedPythonPath;
} else {
// tslint:disable-next-line:no-backbone-get-set-outside-model no-non-null-assertion
this.pythonPath = systemVariables.resolveAny(pythonSettings.get<string>('pythonPath'))!;
}
this.pythonPath = getAbsolutePath(this.pythonPath, workspaceRoot);
// tslint:disable-next-line:no-backbone-get-set-outside-model no-non-null-assertion
this.venvPath = systemVariables.resolveAny(pythonSettings.get<string>('venvPath'))!;
Expand Down Expand Up @@ -348,14 +354,16 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
}
}
protected initialize(): void {
this.disposables.push(workspace.onDidChangeConfiguration(() => {
const onDidChange = () => {
const currentConfig = workspace.getConfiguration('python', this.workspaceRoot);
this.update(currentConfig);

// If workspace config changes, then we could have a cascading effect of on change events.
// Let's defer the change notification.
setTimeout(() => this.emit('change'), 1);
}));
};
this.disposables.push(this.interpreterAutoSeletionService.onDidChangeAutoSelectedInterpreter(onDidChange.bind(this)));
this.disposables.push(workspace.onDidChangeConfiguration(onDidChange.bind(this)));

const initialConfig = workspace.getConfiguration('python', this.workspaceRoot);
if (initialConfig) {
Expand Down
9 changes: 7 additions & 2 deletions src/client/common/configuration/service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { injectable } from 'inversify';
import { inject, injectable } from 'inversify';
import { ConfigurationTarget, Uri, workspace, WorkspaceConfiguration } from 'vscode';
import { IInterpreterAutoSeletionProxyService } from '../../interpreter/interpreterSelection/types';
import { IServiceContainer } from '../../ioc/types';
import { PythonSettings } from '../configSettings';
import { IConfigurationService, IPythonSettings } from '../types';

@injectable()
export class ConfigurationService implements IConfigurationService {
constructor(@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer) { }
public getSettings(resource?: Uri): IPythonSettings {
return PythonSettings.getInstance(resource);
const interpreterAutoSeletionService = this.serviceContainer.get<IInterpreterAutoSeletionProxyService>(IInterpreterAutoSeletionProxyService);
return PythonSettings.getInstance(resource, interpreterAutoSeletionService);
// return PythonSettings.getInstance(resource);
}

public async updateSectionSetting(section: string, setting: string, value?: {}, resource?: Uri, configTarget?: ConfigurationTarget): Promise<void> {
Expand Down
13 changes: 10 additions & 3 deletions src/client/common/platform/registry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { injectable } from 'inversify';
import * as Registry from 'winreg';
import { Options } from 'winreg';
import { Architecture } from '../utils/platform';
import { IRegistry, RegistryHive } from './types';

Expand Down Expand Up @@ -29,7 +29,9 @@ export function getArchitectureDisplayName(arch?: Architecture) {
}
}

async function getRegistryValue(options: Registry.Options, name: string = '') {
async function getRegistryValue(options: Options, name: string = '') {
// tslint:disable-next-line:no-require-imports
const Registry = require('winreg') as typeof import('winreg');
return new Promise<string | undefined | null>((resolve, reject) => {
new Registry(options).get(name, (error, result) => {
if (error || !result || typeof result.value !== 'string') {
Expand All @@ -39,7 +41,10 @@ async function getRegistryValue(options: Registry.Options, name: string = '') {
});
});
}
async function getRegistryKeys(options: Registry.Options): Promise<string[]> {

async function getRegistryKeys(options: Options): Promise<string[]> {
// tslint:disable-next-line:no-require-imports
const Registry = require('winreg') as typeof import('winreg');
// https://github.com/python/peps/blob/master/pep-0514.txt#L85
return new Promise<string[]>((resolve, reject) => {
new Registry(options).keys((error, result) => {
Expand All @@ -61,6 +66,8 @@ function translateArchitecture(arch?: Architecture): RegistryArchitectures | und
}
}
function translateHive(hive: RegistryHive): string | undefined {
// tslint:disable-next-line:no-require-imports
const Registry = require('winreg') as typeof import('winreg');
switch (hive) {
case RegistryHive.HKCU:
return Registry.HKCU;
Expand Down
4 changes: 1 addition & 3 deletions src/client/common/platform/serviceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,5 @@ import { IFileSystem, IPlatformService, IRegistry } from './types';
export function registerTypes(serviceManager: IServiceManager) {
serviceManager.addSingleton<IPlatformService>(IPlatformService, PlatformService);
serviceManager.addSingleton<IFileSystem>(IFileSystem, FileSystem);
if (serviceManager.get<IPlatformService>(IPlatformService).isWindows) {
serviceManager.addSingleton<IRegistry>(IRegistry, RegistryImplementation);
}
serviceManager.addSingleton<IRegistry>(IRegistry, RegistryImplementation);
}
1 change: 1 addition & 0 deletions src/client/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const IMemento = Symbol('IGlobalMemento');
export const GLOBAL_MEMENTO = Symbol('IGlobalMemento');
export const WORKSPACE_MEMENTO = Symbol('IWorkspaceMemento');

export type Resource = Uri | undefined;
export interface IPersistentState<T> {
readonly value: T;
updateValue(value: T): Promise<void>;
Expand Down
6 changes: 4 additions & 2 deletions src/client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import {
InterpreterLocatorProgressHandler,
PythonInterpreter
} from './interpreter/contracts';
import { IInterpreterAutoSeletionService } from './interpreter/interpreterSelection/types';
import { registerTypes as interpretersRegisterTypes } from './interpreter/serviceRegistry';
import { ServiceContainer } from './ioc/container';
import { ServiceManager } from './ioc/serviceManager';
Expand Down Expand Up @@ -109,8 +110,8 @@ export async function activate(context: ExtensionContext): Promise<IExtensionApi
registerServices(context, serviceManager, serviceContainer);
initializeServices(context, serviceManager, serviceContainer);

const interpreterManager = serviceContainer.get<IInterpreterService>(IInterpreterService);
await interpreterManager.autoSetInterpreter();
const autoSelection = serviceContainer.get<IInterpreterAutoSeletionService>(IInterpreterAutoSeletionService);
await autoSelection.autoSelectInterpreter(undefined);

// When testing, do not perform health checks, as modal dialogs can be displayed.
if (!isTestExecution()) {
Expand All @@ -136,6 +137,7 @@ export async function activate(context: ExtensionContext): Promise<IExtensionApi
sendStartupTelemetry(Promise.all([activationDeferred.promise, lsActivationPromise]), serviceContainer).ignoreErrors();

const workspaceService = serviceContainer.get<IWorkspaceService>(IWorkspaceService);
const interpreterManager = serviceContainer.get<IInterpreterService>(IInterpreterService);
interpreterManager.refresh(workspaceService.hasWorkspaceFolders ? workspaceService.workspaceFolders![0].uri : undefined)
.catch(ex => console.error('Python Extension: interpreterManager.refresh', ex));

Expand Down
6 changes: 3 additions & 3 deletions src/client/interpreter/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SemVer } from 'semver';
import { CodeLensProvider, ConfigurationTarget, Disposable, Event, TextDocument, Uri } from 'vscode';
import { InterpreterInfomation } from '../common/process/types';
import { Resource } from '../common/types';

export const INTERPRETER_LOCATOR_SERVICE = 'IInterpreterLocatorService';
export const WINDOWS_REGISTRY_SERVICE = 'WindowsRegistryService';
Expand Down Expand Up @@ -84,13 +85,11 @@ export interface IInterpreterService {
onDidChangeInterpreter: Event<void>;
hasInterpreters: Promise<boolean>;
getInterpreters(resource?: Uri): Promise<PythonInterpreter[]>;
autoSetInterpreter(): Promise<void>;
getActiveInterpreter(resource?: Uri): Promise<PythonInterpreter | undefined>;
getInterpreterDetails(pythonPath: string, resoure?: Uri): Promise<undefined | PythonInterpreter>;
refresh(resource: Uri | undefined): Promise<void>;
initialize(): void;
getDisplayName(interpreter: Partial<PythonInterpreter>): Promise<string>;
shouldAutoSetInterpreter(): Promise<boolean>;
}

export const IInterpreterDisplay = Symbol('IInterpreterDisplay');
Expand All @@ -105,10 +104,11 @@ export interface IShebangCodeLensProvider extends CodeLensProvider {

export const IInterpreterHelper = Symbol('IInterpreterHelper');
export interface IInterpreterHelper {
getActiveWorkspaceUri(): WorkspacePythonPath | undefined;
getActiveWorkspaceUri(resource: Resource): WorkspacePythonPath | undefined;
getInterpreterInformation(pythonPath: string): Promise<undefined | Partial<PythonInterpreter>>;
isMacDefaultPythonPath(pythonPath: string): Boolean;
getInterpreterTypeDisplayName(interpreterType: InterpreterType): string | undefined;
getBestInterpreter(interpreters?: PythonInterpreter[]): PythonInterpreter | undefined;
}

export const IPipEnvService = Symbol('IPipEnvService');
Expand Down
2 changes: 1 addition & 1 deletion src/client/interpreter/display/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class InterpreterDisplay implements IInterpreterDisplay {
resource = this.workspaceService.getWorkspaceFolder(resource)!.uri;
}
if (!resource) {
const wkspc = this.helper.getActiveWorkspaceUri();
const wkspc = this.helper.getActiveWorkspaceUri(resource);
resource = wkspc ? wkspc.folderUri : undefined;
}
await this.updateDisplay(resource);
Expand Down
23 changes: 19 additions & 4 deletions src/client/interpreter/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ConfigurationTarget } from 'vscode';
import { IDocumentManager, IWorkspaceService } from '../common/application/types';
import { IFileSystem } from '../common/platform/types';
import { InterpreterInfomation, IPythonExecutionFactory } from '../common/process/types';
import { IPersistentStateFactory } from '../common/types';
import { IPersistentStateFactory, Resource } from '../common/types';
import { IServiceContainer } from '../ioc/types';
import { IInterpreterHelper, InterpreterType, PythonInterpreter, WorkspacePythonPath } from './contracts';

Expand All @@ -26,16 +26,23 @@ export class InterpreterHelper implements IInterpreterHelper {
this.persistentFactory = this.serviceContainer.get<IPersistentStateFactory>(IPersistentStateFactory);
this.fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
}
public getActiveWorkspaceUri(): WorkspacePythonPath | undefined {
public getActiveWorkspaceUri(resource: Resource): WorkspacePythonPath | undefined {
const workspaceService = this.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
const documentManager = this.serviceContainer.get<IDocumentManager>(IDocumentManager);

if (!workspaceService.hasWorkspaceFolders) {
return;
}
if (Array.isArray(workspaceService.workspaceFolders) && workspaceService.workspaceFolders.length === 1) {
return { folderUri: workspaceService.workspaceFolders[0].uri, configTarget: ConfigurationTarget.Workspace };
}

if (resource) {
const workspaceFolder = workspaceService.getWorkspaceFolder(resource);
if (workspaceFolder) {
return { configTarget: ConfigurationTarget.WorkspaceFolder, folderUri: workspaceFolder.uri };
}
}
const documentManager = this.serviceContainer.get<IDocumentManager>(IDocumentManager);

if (documentManager.activeTextEditor) {
const workspaceFolder = workspaceService.getWorkspaceFolder(documentManager.activeTextEditor.document.uri);
if (workspaceFolder) {
Expand Down Expand Up @@ -93,4 +100,12 @@ export class InterpreterHelper implements IInterpreterHelper {
}
}
}
public getBestInterpreter(interpreters?: PythonInterpreter[]): PythonInterpreter | undefined {
if (!Array.isArray(interpreters) || interpreters.length === 0) {
return;
}
const sorted = interpreters.slice();
sorted.sort((a, b) => (a.version && b.version) ? a.version.compare(b.version) : 0);
return sorted[sorted.length - 1];
}
}
Loading

0 comments on commit 2bc224e

Please sign in to comment.