add wslFeatureInstalled context key (#160424)

* add wslFeatureInstalled context key

* only register the contribution when on windows

* add doc

* wait for LifecyclePhase#Eventually
This commit is contained in:
Martin Aeschlimann
2022-09-09 10:11:14 +02:00
committed by GitHub
parent 0dce868b85
commit 746fda3a60
5 changed files with 125 additions and 2 deletions
+2
View File
@@ -121,6 +121,8 @@ export interface ICommonNativeHostService {
getOSColorScheme(): Promise<IColorScheme>;
hasWSLFeatureInstalled(): Promise<boolean>;
// Process
killProcess(pid: number, code: string): Promise<void>;
@@ -40,6 +40,7 @@ import { IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-m
import { isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService';
import { VSBuffer } from 'vs/base/common/buffer';
import { hasWSLFeatureInstalled } from 'vs/platform/remote/node/wsl';
export interface INativeHostMainService extends AddFirstParameterToFunctions<ICommonNativeHostService, Promise<unknown> /* only methods, not events */, number | undefined /* window ID */> { }
@@ -568,6 +569,12 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
}
// WSL
public async hasWSLFeatureInstalled(): Promise<boolean> {
return isWindows && hasWSLFeatureInstalled();
}
//#endregion
+72
View File
@@ -0,0 +1,72 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
import * as cp from 'child_process';
import { promises as fs } from 'fs';
import path = require('path');
let hasWSLFeaturePromise: Promise<boolean> | undefined;
export async function hasWSLFeatureInstalled(refresh = false): Promise<boolean> {
if (hasWSLFeaturePromise === undefined || refresh) {
hasWSLFeaturePromise = testWSLFeatureInstalled();
}
return hasWSLFeaturePromise;
}
async function testWSLFeatureInstalled(): Promise<boolean> {
const windowsBuildNumber = getWindowsBuildNumber();
if (windowsBuildNumber === undefined) {
return false;
}
if (windowsBuildNumber >= 22000) {
const wslExePath = getWSLExecutablePath();
if (wslExePath) {
return new Promise<boolean>(s => {
cp.execFile(wslExePath, ['--status'], err => s(!err));
});
}
} else {
const dllPath = getLxssManagerDllPath();
if (dllPath) {
try {
if ((await fs.stat(dllPath)).isFile()) {
return true;
}
} catch (e) {
}
}
}
return false;
}
function getWindowsBuildNumber(): number | undefined {
const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release());
if (osVersion) {
return parseInt(osVersion[3]);
}
return undefined;
}
function getSystem32Path(subPath: string): string | undefined {
const systemRoot = process.env['SystemRoot'];
if (systemRoot) {
const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
return path.join(systemRoot, is32ProcessOn64Windows ? 'Sysnative' : 'System32', subPath);
}
return undefined;
}
function getWSLExecutablePath(): string | undefined {
return getSystem32Path('wsl.exe');
}
/**
* In builds < 22000 this dll inidcates that WSL is installed
*/
function getLxssManagerDllPath(): string | undefined {
return getSystem32Path('lxss\\LxssManager.dll');
}
@@ -7,11 +7,11 @@ import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { Disposable } from 'vs/base/common/lifecycle';
import { isMacintosh } from 'vs/base/common/platform';
import { isMacintosh, isWindows } from 'vs/base/common/platform';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchContributionsExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { ILabelService } from 'vs/platform/label/common/label';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { Schemas } from 'vs/base/common/network';
@@ -27,6 +27,9 @@ import { OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderComman
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry';
import { getTelemetryLevel } from 'vs/platform/telemetry/common/telemetryUtils';
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
class RemoteAgentDiagnosticListener implements IWorkbenchContribution {
constructor(
@@ -131,11 +134,49 @@ class RemoteEmptyWorkbenchPresentation extends Disposable implements IWorkbenchC
}
}
/**
* Sets the 'wslFeatureInstalled' context key if the WSL feature is or was installed on this machine.
*/
class WSLContextKeyInitializer extends Disposable implements IWorkbenchContribution {
constructor(
@IContextKeyService contextKeyService: IContextKeyService,
@INativeHostService nativeHostService: INativeHostService,
@IStorageService storageService: IStorageService,
@ILifecycleService lifecycleService: ILifecycleService
) {
super();
const contextKeyId = 'wslFeatureInstalled';
const storageKey = 'remote.wslFeatureInstalled';
const defaultValue = storageService.getBoolean(storageKey, StorageScope.APPLICATION, undefined);
const hasWSLFeatureContext = new RawContextKey<boolean>(contextKeyId, !!defaultValue, nls.localize('wslFeatureInstalled', "Whether the platform has the WSL feature installed"));
const contextKey = hasWSLFeatureContext.bindTo(contextKeyService);
if (defaultValue === undefined) {
lifecycleService.when(LifecyclePhase.Eventually).then(async () => {
nativeHostService.hasWSLFeatureInstalled().then(res => {
if (res) {
contextKey.set(true);
// once detected, set to true
storageService.store(storageKey, true, StorageScope.APPLICATION, StorageTarget.MACHINE);
}
});
});
}
}
}
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchContributionsExtensions.Workbench);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentDiagnosticListener, 'RemoteAgentDiagnosticListener', LifecyclePhase.Eventually);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteExtensionHostEnvironmentUpdater, 'RemoteExtensionHostEnvironmentUpdater', LifecyclePhase.Eventually);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteTelemetryEnablementUpdater, 'RemoteTelemetryEnablementUpdater', LifecyclePhase.Ready);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteEmptyWorkbenchPresentation, 'RemoteEmptyWorkbenchPresentation', LifecyclePhase.Ready);
if (isWindows) {
workbenchContributionsRegistry.registerWorkbenchContribution(WSLContextKeyInitializer, 'WSLContextKeyInitializer', LifecyclePhase.Ready);
}
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
.registerConfiguration({
@@ -240,6 +240,7 @@ export class TestNativeHostService implements INativeHostService {
async getOSStatistics(): Promise<IOSStatistics> { return Object.create(null); }
async getOSVirtualMachineHint(): Promise<number> { return 0; }
async getOSColorScheme(): Promise<IColorScheme> { return { dark: true, highContrast: false }; }
async hasWSLFeatureInstalled(): Promise<boolean> { return false; }
async killProcess(): Promise<void> { }
async setDocumentEdited(edited: boolean): Promise<void> { }
async openExternal(url: string): Promise<boolean> { return false; }