Merge from vscode e3c4990c67c40213af168300d1cfeb71d680f877 (#16569)

This commit is contained in:
Cory Rivera
2021-08-25 16:28:29 -07:00
committed by GitHub
parent ab1112bfb3
commit cb7b7da0a4
1752 changed files with 59525 additions and 33878 deletions

View File

@@ -278,8 +278,8 @@ class WorkspaceProvider implements IWorkspaceProvider {
readonly trusted = true;
constructor(
public readonly workspace: IWorkspace,
public readonly payload: object
readonly workspace: IWorkspace,
readonly payload: object
) { }
async open(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): Promise<boolean> {

View File

@@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { basename, dirname, join } from 'vs/base/common/path';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Disposable } from 'vs/base/common/lifecycle';
import { Promises } from 'vs/base/node/pfs';
import { IProductService } from 'vs/platform/product/common/productService';
import { RunOnceScheduler } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
export class CodeCacheCleaner extends Disposable {
private readonly _DataMaxAge = this.productService.quality !== 'stable'
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders)
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable)
constructor(
currentCodeCachePath: string | undefined,
@IProductService private readonly productService: IProductService,
@ILogService private readonly logService: ILogService
) {
super();
// Cached data is stored as user data and we run a cleanup task everytime
// the editor starts. The strategy is to delete all files that are older than
// 3 months (1 week respectively)
if (currentCodeCachePath) {
const scheduler = this._register(new RunOnceScheduler(() => {
this.cleanUpCodeCaches(currentCodeCachePath);
}, 30 * 1000 /* after 30s */));
scheduler.schedule();
}
}
private async cleanUpCodeCaches(currentCodeCachePath: string): Promise<void> {
this.logService.info('[code cache cleanup]: Starting to clean up old code cache folders.');
try {
const now = Date.now();
// The folder which contains folders of cached data.
// Each of these folders is partioned per commit
const codeCacheRootPath = dirname(currentCodeCachePath);
const currentCodeCache = basename(currentCodeCachePath);
const codeCaches = await Promises.readdir(codeCacheRootPath);
await Promise.all(codeCaches.map(async codeCache => {
if (codeCache === currentCodeCache) {
return; // not the current cache folder
}
// Delete cache folder if old enough
const codeCacheEntryPath = join(codeCacheRootPath, codeCache);
const codeCacheEntryStat = await Promises.stat(codeCacheEntryPath);
if (codeCacheEntryStat.isDirectory() && (now - codeCacheEntryStat.mtime.getTime()) > this._DataMaxAge) {
this.logService.info(`[code cache cleanup]: Removing code cache folder ${codeCache}.`);
return Promises.rm(codeCacheEntryPath);
}
}));
} catch (error) {
onUnexpectedError(error);
}
}
}

View File

@@ -3,17 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import * as path from 'vs/base/common/path';
import * as pfs from 'vs/base/node/pfs';
import { join } from 'vs/base/common/path';
import { Promises } from 'vs/base/node/pfs';
import { IStringDictionary } from 'vs/base/common/collections';
import { IProductService } from 'vs/platform/product/common/productService';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ILogService } from 'vs/platform/log/common/log';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { RunOnceScheduler } from 'vs/base/common/async';
interface ExtensionEntry {
interface IExtensionEntry {
version: string;
extensionIdentifier: {
id: string;
@@ -21,87 +21,88 @@ interface ExtensionEntry {
};
}
interface LanguagePackEntry {
interface ILanguagePackEntry {
hash: string;
extensions: ExtensionEntry[];
extensions: IExtensionEntry[];
}
interface LanguagePackFile {
[locale: string]: LanguagePackEntry;
interface ILanguagePackFile {
[locale: string]: ILanguagePackEntry;
}
export class LanguagePackCachedDataCleaner extends Disposable {
private readonly _DataMaxAge = this._productService.quality !== 'stable'
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months
private readonly _DataMaxAge = this.productService.quality !== 'stable'
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders)
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable)
constructor(
@INativeEnvironmentService private readonly _environmentService: INativeEnvironmentService,
@ILogService private readonly _logService: ILogService,
@IProductService private readonly _productService: IProductService
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
@ILogService private readonly logService: ILogService,
@IProductService private readonly productService: IProductService
) {
super();
// We have no Language pack support for dev version (run from source)
// So only cleanup when we have a build version.
if (this._environmentService.isBuilt) {
this._manageCachedDataSoon();
if (this.environmentService.isBuilt) {
const scheduler = this._register(new RunOnceScheduler(() => {
this.cleanUpLanguagePackCache();
}, 40 * 1000 /* after 40s */));
scheduler.schedule();
}
}
private _manageCachedDataSoon(): void {
let handle: any = setTimeout(async () => {
handle = undefined;
this._logService.info('Starting to clean up unused language packs.');
try {
const installed: IStringDictionary<boolean> = Object.create(null);
const metaData: LanguagePackFile = JSON.parse(await fs.promises.readFile(path.join(this._environmentService.userDataPath, 'languagepacks.json'), 'utf8'));
for (let locale of Object.keys(metaData)) {
const entry = metaData[locale];
installed[`${entry.hash}.${locale}`] = true;
private async cleanUpLanguagePackCache(): Promise<void> {
this.logService.info('[language pack cache cleanup]: Starting to clean up unused language packs.');
try {
const installed: IStringDictionary<boolean> = Object.create(null);
const metaData: ILanguagePackFile = JSON.parse(await Promises.readFile(join(this.environmentService.userDataPath, 'languagepacks.json'), 'utf8'));
for (let locale of Object.keys(metaData)) {
const entry = metaData[locale];
installed[`${entry.hash}.${locale}`] = true;
}
// Cleanup entries for language packs that aren't installed anymore
const cacheDir = join(this.environmentService.userDataPath, 'clp');
const cacheDirExists = await Promises.exists(cacheDir);
if (!cacheDirExists) {
return;
}
const entries = await Promises.readdir(cacheDir);
for (const entry of entries) {
if (installed[entry]) {
this.logService.info(`[language pack cache cleanup]: Skipping folder ${entry}. Language pack still in use.`);
continue;
}
// Cleanup entries for language packs that aren't installed anymore
const cacheDir = path.join(this._environmentService.userDataPath, 'clp');
const exists = await pfs.exists(cacheDir);
if (!exists) {
return;
}
for (let entry of await pfs.readdir(cacheDir)) {
if (installed[entry]) {
this._logService.info(`Skipping directory ${entry}. Language pack still in use.`);
this.logService.info(`[language pack cache cleanup]: Removing unused language pack: ${entry}`);
await Promises.rm(join(cacheDir, entry));
}
const now = Date.now();
for (const packEntry of Object.keys(installed)) {
const folder = join(cacheDir, packEntry);
const entries = await Promises.readdir(folder);
for (const entry of entries) {
if (entry === 'tcf.json') {
continue;
}
this._logService.info('Removing unused language pack:', entry);
await pfs.rimraf(path.join(cacheDir, entry));
}
const now = Date.now();
for (let packEntry of Object.keys(installed)) {
const folder = path.join(cacheDir, packEntry);
for (let entry of await pfs.readdir(folder)) {
if (entry === 'tcf.json') {
continue;
}
const candidate = path.join(folder, entry);
const stat = await fs.promises.stat(candidate);
if (stat.isDirectory()) {
const diff = now - stat.mtime.getTime();
if (diff > this._DataMaxAge) {
this._logService.info('Removing language pack cache entry: ', path.join(packEntry, entry));
await pfs.rimraf(candidate);
}
}
const candidate = join(folder, entry);
const stat = await Promises.stat(candidate);
if (stat.isDirectory() && (now - stat.mtime.getTime()) > this._DataMaxAge) {
this.logService.info(`[language pack cache cleanup]: Removing language pack cache folder: ${join(packEntry, entry)}`);
await Promises.rm(candidate);
}
}
} catch (error) {
onUnexpectedError(error);
}
}, 40 * 1000);
this._register(toDisposable(() => {
if (handle !== undefined) {
clearTimeout(handle);
}
}));
} catch (error) {
onUnexpectedError(error);
}
}
}

View File

@@ -5,42 +5,46 @@
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { join, dirname, basename } from 'vs/base/common/path';
import { readdir, rimraf } from 'vs/base/node/pfs';
import { Promises } from 'vs/base/node/pfs';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Promises } from 'vs/base/common/async';
import { Disposable } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
export class LogsDataCleaner extends Disposable {
constructor(
@IEnvironmentService private readonly environmentService: IEnvironmentService
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ILogService private readonly logService: ILogService
) {
super();
this.cleanUpOldLogsSoon();
const scheduler = this._register(new RunOnceScheduler(() => {
this.cleanUpOldLogs();
}, 10 * 1000 /* after 10s */));
scheduler.schedule();
}
private cleanUpOldLogsSoon(): void {
let handle: NodeJS.Timeout | undefined = setTimeout(() => {
handle = undefined;
private async cleanUpOldLogs(): Promise<void> {
this.logService.info('[logs cleanup]: Starting to clean up old logs.');
try {
const currentLog = basename(this.environmentService.logsPath);
const logsRoot = dirname(this.environmentService.logsPath);
readdir(logsRoot).then(children => {
const allSessions = children.filter(name => /^\d{8}T\d{6}$/.test(name));
const oldSessions = allSessions.sort().filter((d, i) => d !== currentLog);
const toDelete = oldSessions.slice(0, Math.max(0, oldSessions.length - 9));
const logFiles = await Promises.readdir(logsRoot);
return Promises.settled(toDelete.map(name => rimraf(join(logsRoot, name))));
}).then(null, onUnexpectedError);
}, 10 * 1000);
const allSessions = logFiles.filter(logFile => /^\d{8}T\d{6}$/.test(logFile));
const oldSessions = allSessions.sort().filter(session => session !== currentLog);
const sessionsToDelete = oldSessions.slice(0, Math.max(0, oldSessions.length - 9));
this._register(toDisposable(() => {
if (handle) {
clearTimeout(handle);
handle = undefined;
if (sessionsToDelete.length > 0) {
this.logService.info(`[logs cleanup]: Removing log folders '${sessionsToDelete.join(', ')}'`);
await Promise.all(sessionsToDelete.map(sessionToDelete => Promises.rm(join(logsRoot, sessionToDelete))));
}
}));
} catch (error) {
onUnexpectedError(error);
}
}
}

View File

@@ -1,87 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { promises } from 'fs';
import { basename, dirname, join } from 'vs/base/common/path';
import { onUnexpectedError } from 'vs/base/common/errors';
import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { readdir, rimraf } from 'vs/base/node/pfs';
import { IProductService } from 'vs/platform/product/common/productService';
export class NodeCachedDataCleaner {
private readonly _DataMaxAge = this.productService.quality !== 'stable'
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months
private readonly _disposables = new DisposableStore();
constructor(
private readonly nodeCachedDataDir: string | undefined,
@IProductService private readonly productService: IProductService
) {
this._manageCachedDataSoon();
}
dispose(): void {
this._disposables.dispose();
}
private _manageCachedDataSoon(): void {
// Cached data is stored as user data and we run a cleanup task everytime
// the editor starts. The strategy is to delete all files that are older than
// 3 months (1 week respectively)
if (!this.nodeCachedDataDir) {
return;
}
// The folder which contains folders of cached data. Each of these folder is per
// version
const nodeCachedDataRootDir = dirname(this.nodeCachedDataDir);
const nodeCachedDataCurrent = basename(this.nodeCachedDataDir);
let handle: NodeJS.Timeout | undefined = setTimeout(() => {
handle = undefined;
readdir(nodeCachedDataRootDir).then(entries => {
const now = Date.now();
const deletes: Promise<unknown>[] = [];
entries.forEach(entry => {
// name check
// * not the current cached data folder
if (entry !== nodeCachedDataCurrent) {
const path = join(nodeCachedDataRootDir, entry);
deletes.push(promises.stat(path).then(stats => {
// stat check
// * only directories
// * only when old enough
if (stats.isDirectory()) {
const diff = now - stats.mtime.getTime();
if (diff > this._DataMaxAge) {
return rimraf(path);
}
}
return undefined;
}));
}
});
return Promise.all(deletes);
}).then(undefined, onUnexpectedError);
}, 30 * 1000);
this._disposables.add(toDisposable(() => {
if (handle) {
clearTimeout(handle);
handle = undefined;
}
}));
}
}

View File

@@ -3,13 +3,14 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { promises } from 'fs';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { join } from 'vs/base/common/path';
import { readdir, rimraf } from 'vs/base/node/pfs';
import { Promises } from 'vs/base/node/pfs';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { IBackupWorkspacesFormat } from 'vs/platform/backup/node/backup';
import { RunOnceScheduler } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
export class StorageDataCleaner extends Disposable {
@@ -18,52 +19,44 @@ export class StorageDataCleaner extends Disposable {
constructor(
private readonly backupWorkspacesPath: string,
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
@ILogService private readonly logService: ILogService
) {
super();
this.cleanUpStorageSoon();
const scheduler = this._register(new RunOnceScheduler(() => {
this.cleanUpStorage();
}, 30 * 1000 /* after 30s */));
scheduler.schedule();
}
private cleanUpStorageSoon(): void {
let handle: NodeJS.Timeout | undefined = setTimeout(() => {
handle = undefined;
private async cleanUpStorage(): Promise<void> {
this.logService.info('[storage cleanup]: Starting to clean up storage folders.');
(async () => {
try {
// Leverage the backup workspace file to find out which empty workspace is currently in use to
// determine which empty workspace storage can safely be deleted
const contents = await promises.readFile(this.backupWorkspacesPath, 'utf8');
try {
const workspaces = JSON.parse(contents) as IBackupWorkspacesFormat;
const emptyWorkspaces = workspaces.emptyWorkspaceInfos.map(info => info.backupFolder);
// Leverage the backup workspace file to find out which empty workspace is currently in use to
// determine which empty workspace storage can safely be deleted
const contents = await Promises.readFile(this.backupWorkspacesPath, 'utf8');
// Read all workspace storage folders that exist
const storageFolders = await readdir(this.environmentService.workspaceStorageHome.fsPath);
const deletes: Promise<void>[] = [];
const workspaces = JSON.parse(contents) as IBackupWorkspacesFormat;
const emptyWorkspaces = workspaces.emptyWorkspaceInfos.map(emptyWorkspace => emptyWorkspace.backupFolder);
storageFolders.forEach(storageFolder => {
if (storageFolder.length === StorageDataCleaner.NON_EMPTY_WORKSPACE_ID_LENGTH) {
return;
}
if (emptyWorkspaces.indexOf(storageFolder) === -1) {
deletes.push(rimraf(join(this.environmentService.workspaceStorageHome.fsPath, storageFolder)));
}
});
await Promise.all(deletes);
} catch (error) {
onUnexpectedError(error);
// Read all workspace storage folders that exist
const storageFolders = await Promises.readdir(this.environmentService.workspaceStorageHome.fsPath);
await Promise.all(storageFolders.map(async storageFolder => {
if (storageFolder.length === StorageDataCleaner.NON_EMPTY_WORKSPACE_ID_LENGTH) {
return;
}
})();
}, 30 * 1000);
this._register(toDisposable(() => {
if (handle) {
clearTimeout(handle);
handle = undefined;
}
}));
if (emptyWorkspaces.indexOf(storageFolder) === -1) {
this.logService.info(`[storage cleanup]: Deleting storage folder ${storageFolder}.`);
await Promises.rm(join(this.environmentService.workspaceStorageHome.fsPath, storageFolder));
}
}));
} catch (error) {
onUnexpectedError(error);
}
}
}

View File

@@ -46,10 +46,7 @@
* forceEnableDeveloperKeybindings?: boolean,
* disallowReloadKeybinding?: boolean,
* removeDeveloperKeybindingsAfterLoad?: boolean
* },
* canModifyDOM?: (config: ISandboxConfiguration) => void,
* beforeLoaderConfig?: (loaderConfig: object) => void,
* beforeRequire?: () => void
* }
* }
* ) => Promise<unknown>
* }}

View File

@@ -36,7 +36,7 @@ import { ILocalizationsService } from 'vs/platform/localizations/common/localiza
import { combinedDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { DownloadService } from 'vs/platform/download/common/downloadService';
import { IDownloadService } from 'vs/platform/download/common/download';
import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner';
import { CodeCacheCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/codeCacheCleaner';
import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner';
import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner';
import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner';
@@ -77,7 +77,7 @@ import { LocalizationsUpdater } from 'vs/code/electron-browser/sharedProcess/con
import { DeprecatedExtensionsCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/deprecatedExtensionsCleaner';
import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal';
import { LocalReconnectConstants, TerminalIpcChannels } from 'vs/platform/terminal/common/terminal';
import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService';
import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal';
import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncServiceIpc';
@@ -131,7 +131,7 @@ class SharedProcessMain extends Disposable {
// Instantiate Contributions
this._register(combinedDisposable(
instantiationService.createInstance(NodeCachedDataCleaner, this.configuration.nodeCachedDataDir),
instantiationService.createInstance(CodeCacheCleaner, this.configuration.codeCachePath),
instantiationService.createInstance(LanguagePackCachedDataCleaner),
instantiationService.createInstance(StorageDataCleaner, this.configuration.backupWorkspacesPath),
instantiationService.createInstance(LogsDataCleaner),
@@ -272,7 +272,19 @@ class SharedProcessMain extends Disposable {
services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService));
// Terminal
services.set(ILocalPtyService, this._register(new PtyHostService(logService, telemetryService)));
services.set(
ILocalPtyService,
this._register(
new PtyHostService({
GraceTime: LocalReconnectConstants.GraceTime,
ShortGraceTime: LocalReconnectConstants.ShortGraceTime
},
configurationService,
logService,
telemetryService
)
)
);
return new InstantiationService(services);
}

View File

@@ -4,7 +4,7 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote-resource:; media-src 'none'; frame-src 'self' vscode-webview:; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https: ws:; font-src 'self' https: vscode-remote-resource:;">
<!-- <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types default TrustedFunctionWorkaround ExtensionScripts amdLoader cellRendererEditorText defaultWorkerFactory diffEditorWidget domLineBreaksComputer editorViewLayer diffReview extensionHostWorker insane notebookOutputRenderer safeInnerHtml standaloneColorizer tokenizeToString webNestedWorkerExtensionHost webWorkerExtensionHost;"> {{SQL CARBON EDIT}} TODO @chgagnon Comment out until we can investigate a proper fix for ADS not starting up -->
<!-- <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types default TrustedFunctionWorkaround ExtensionScripts amdLoader cellRendererEditorText defaultWorkerFactory diffEditorWidget editorGhostText domLineBreaksComputer editorViewLayer diffReview extensionHostWorker insane notebookRenderer safeInnerHtml standaloneColorizer tokenizeToString webNestedWorkerExtensionHost webWorkerExtensionHost;"> {{SQL CARBON EDIT}} TODO @chgagnon Comment out until we can investigate a proper fix for ADS not starting up -->
</head>
<body aria-label="">
</body>

View File

@@ -44,7 +44,7 @@
};
},
canModifyDOM: function (windowConfig) {
showPartsSplash(windowConfig);
showSplash(windowConfig);
},
beforeLoaderConfig: function (loaderConfig) {
loaderConfig.recordStats = true;
@@ -90,19 +90,20 @@
/**
* @typedef {import('../../../platform/windows/common/windows').INativeWindowConfiguration} INativeWindowConfiguration
* @typedef {import('../../../platform/environment/common/argv').NativeParsedArgs} NativeParsedArgs
*
* @returns {{
* load: (
* modules: string[],
* resultCallback: (result, configuration: INativeWindowConfiguration) => unknown,
* resultCallback: (result, configuration: INativeWindowConfiguration & NativeParsedArgs) => unknown,
* options?: {
* configureDeveloperSettings?: (config: INativeWindowConfiguration & object) => {
* configureDeveloperSettings?: (config: INativeWindowConfiguration & NativeParsedArgs) => {
* forceDisableShowDevtoolsOnError?: boolean,
* forceEnableDeveloperKeybindings?: boolean,
* disallowReloadKeybinding?: boolean,
* removeDeveloperKeybindingsAfterLoad?: boolean
* },
* canModifyDOM?: (config: INativeWindowConfiguration & object) => void,
* canModifyDOM?: (config: INativeWindowConfiguration & NativeParsedArgs) => void,
* beforeLoaderConfig?: (loaderConfig: object) => void,
* beforeRequire?: () => void
* }
@@ -115,28 +116,15 @@
}
/**
* @param {{
* partsSplashPath?: string,
* colorScheme: ('light' | 'dark' | 'hc'),
* autoDetectHighContrast?: boolean,
* extensionDevelopmentPath?: string[],
* workspace?: import('../../../platform/workspaces/common/workspaces').IWorkspaceIdentifier | import('../../../platform/workspaces/common/workspaces').ISingleFolderWorkspaceIdentifier
* }} configuration
* @param {INativeWindowConfiguration & NativeParsedArgs} configuration
*/
function showPartsSplash(configuration) {
function showSplash(configuration) {
performance.mark('code/willShowPartsSplash');
let data;
if (typeof configuration.partsSplashPath === 'string') {
try {
data = JSON.parse(require.__$__nodeRequire('fs').readFileSync(configuration.partsSplashPath, 'utf8'));
} catch (e) {
// ignore
}
}
let data = configuration.partsSplash;
// high contrast mode has been turned on from the outside, e.g. OS -> ignore stored colors and layouts
const isHighContrast = configuration.colorScheme === 'hc' /* ColorScheme.HIGH_CONTRAST */ && configuration.autoDetectHighContrast;
const isHighContrast = configuration.colorScheme.highContrast && configuration.autoDetectHighContrast;
if (data && isHighContrast && data.baseTheme !== 'hc-black') {
data = undefined;
}
@@ -161,16 +149,18 @@
shellBackground = '#1E1E1E';
shellForeground = '#CCCCCC';
}
const style = document.createElement('style');
style.className = 'initialShellColors';
document.head.appendChild(style);
style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`;
if (data && data.layoutInfo) {
// restore parts if possible (we might not always store layout info)
const { id, layoutInfo, colorInfo } = data;
// restore parts if possible (we might not always store layout info)
if (data?.layoutInfo) {
const { layoutInfo, colorInfo } = data;
const splash = document.createElement('div');
splash.id = id;
splash.id = 'monaco-parts-splash';
splash.className = baseTheme;
if (layoutInfo.windowBorder) {
@@ -199,8 +189,8 @@
splash.appendChild(activityDiv);
// part: side bar (only when opening workspace/folder)
// folder or workspace -> status bar color, sidebar
if (configuration.workspace) {
// folder or workspace -> status bar color, sidebar
const sideDiv = document.createElement('div');
sideDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; width: ${layoutInfo.sideBarWidth}px; background-color: ${colorInfo.sideBarBackground};`);
splash.appendChild(sideDiv);

View File

@@ -5,7 +5,7 @@
import { release, hostname } from 'os';
import { statSync } from 'fs';
import { app, ipcMain, systemPreferences, contentTracing, protocol, BrowserWindow, dialog, session } from 'electron';
import { app, ipcMain, systemPreferences, contentTracing, protocol, BrowserWindow, dialog, session, Session } from 'electron';
import { IProcessEnvironment, isWindows, isMacintosh, isLinux, isLinuxSnap } from 'vs/base/common/platform';
import { WindowsMainService } from 'vs/platform/windows/electron-main/windowsMainService';
import { IWindowOpenable } from 'vs/platform/windows/common/windows';
@@ -23,7 +23,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ILoggerService, ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/node/state';
import { IStateMainService } from 'vs/platform/state/electron-main/state';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IOpenURLOptions, IURLService } from 'vs/platform/url/common/url';
@@ -71,7 +71,7 @@ import { withNullAsUndefined } from 'vs/base/common/types';
import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels';
import { WebviewMainService } from 'vs/platform/webview/electron-main/webviewMainService';
import { IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService';
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
import { IFileService } from 'vs/platform/files/common/files';
import { stripComments } from 'vs/base/common/json';
import { generateUuid } from 'vs/base/common/uuid';
import { VSBuffer } from 'vs/base/common/buffer';
@@ -81,12 +81,14 @@ import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platfo
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
import { isEqualOrParent } from 'vs/base/common/extpath';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
import { ExtensionUrlTrustService } from 'vs/platform/extensionManagement/node/extensionUrlTrustService';
import { once } from 'vs/base/common/functional';
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { ISignService } from 'vs/platform/sign/common/sign';
import { IExternalTerminalMainService } from 'vs/platform/externalTerminal/common/externalTerminal';
import { LinuxExternalTerminalService, MacExternalTerminalService, WindowsExternalTerminalService } from 'vs/platform/externalTerminal/node/externalTerminalService';
/**
* The main VS Code application. There will only ever be one instance,
@@ -105,15 +107,66 @@ export class CodeApplication extends Disposable {
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IStateService private readonly stateService: IStateService,
@IStateMainService private readonly stateMainService: IStateMainService,
@IFileService private readonly fileService: IFileService,
@IProductService private readonly productService: IProductService
) {
super();
this.configureSession();
this.registerListeners();
}
private configureSession(): void {
//#region Security related measures (https://electronjs.org/docs/tutorial/security)
//
// !!! DO NOT CHANGE without consulting the documentation !!!
//
const isUrlFromWebview = (requestingUrl: string) => requestingUrl.startsWith(`${Schemas.vscodeWebview}://`);
session.defaultSession.setPermissionRequestHandler((_webContents, permission /* 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' */, callback, details) => {
if (isUrlFromWebview(details.requestingUrl)) {
return callback(permission === 'clipboard-read');
}
return callback(false);
});
session.defaultSession.setPermissionCheckHandler((_webContents, permission /* 'media' */, _origin, details) => {
if (isUrlFromWebview(details.requestingUrl)) {
return permission === 'clipboard-read';
}
return false;
});
//#endregion
//#region Code Cache
type SessionWithCodeCachePathSupport = typeof Session & {
/**
* Sets code cache directory. By default, the directory will be `Code Cache` under
* the respective user data folder.
*/
setCodeCachePath?(path: string): void;
};
const defaultSession = session.defaultSession as unknown as SessionWithCodeCachePathSupport;
if (typeof defaultSession.setCodeCachePath === 'function' && this.environmentMainService.codeCachePath) {
// Make sure to partition Chrome's code cache folder
// in the same way as our code cache path to help
// invalidate caches that we know are invalid
// (https://github.com/microsoft/vscode/issues/120655)
defaultSession.setCodeCachePath(join(this.environmentMainService.codeCachePath, 'chrome'));
}
//#endregion
}
private registerListeners(): void {
// We handle uncaught exceptions here to prevent electron from opening a dialog to the user
@@ -146,37 +199,6 @@ export class CodeApplication extends Disposable {
//
// !!! DO NOT CHANGE without consulting the documentation !!!
//
app.on('remote-require', (event, sender, module) => {
this.logService.trace('app#on(remote-require): prevented');
event.preventDefault();
});
app.on('remote-get-global', (event, sender, module) => {
this.logService.trace(`app#on(remote-get-global): prevented on ${module}`);
event.preventDefault();
});
app.on('remote-get-builtin', (event, sender, module) => {
this.logService.trace(`app#on(remote-get-builtin): prevented on ${module}`);
if (module !== 'clipboard') {
event.preventDefault();
}
});
app.on('remote-get-current-window', event => {
this.logService.trace(`app#on(remote-get-current-window): prevented`);
event.preventDefault();
});
app.on('remote-get-current-web-contents', event => {
if (this.environmentMainService.args.driver) {
return; // the driver needs access to web contents
}
this.logService.trace(`app#on(remote-get-current-web-contents): prevented`);
event.preventDefault();
});
app.on('web-contents-created', (event, contents) => {
contents.on('will-attach-webview', (event, webPreferences, params) => {
@@ -220,34 +242,17 @@ export class CodeApplication extends Disposable {
event.preventDefault();
});
contents.on('new-window', (event, url) => {
event.preventDefault(); // prevent code that wants to open links
contents.setWindowOpenHandler(({ url }) => {
this.nativeHostMainService?.openExternal(undefined, url);
});
const isUrlFromWebview = (requestingUrl: string) =>
requestingUrl.startsWith(`${Schemas.vscodeWebview}://`);
session.defaultSession.setPermissionRequestHandler((_webContents, permission /* 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' */, callback, details) => {
if (isUrlFromWebview(details.requestingUrl)) {
return callback(permission === 'clipboard-read');
}
return callback(false);
});
session.defaultSession.setPermissionCheckHandler((_webContents, permission /* 'media' */, _origin, details) => {
if (isUrlFromWebview(details.requestingUrl)) {
return permission === 'clipboard-read';
}
return false;
return { action: 'deny' };
});
});
//#endregion
let macOpenFileURIs: IWindowOpenable[] = [];
let runningTimeout: NodeJS.Timeout | null = null;
let runningTimeout: NodeJS.Timeout | undefined = undefined;
app.on('open-file', (event, path) => {
this.logService.trace('app#open-file: ', path);
event.preventDefault();
@@ -256,9 +261,9 @@ export class CodeApplication extends Disposable {
macOpenFileURIs.push(this.getWindowOpenableFromPathSync(path));
// Clear previous handler if any
if (runningTimeout !== null) {
if (runningTimeout !== undefined) {
clearTimeout(runningTimeout);
runningTimeout = null;
runningTimeout = undefined;
}
// Handle paths delayed in case more are coming!
@@ -272,7 +277,7 @@ export class CodeApplication extends Disposable {
});
macOpenFileURIs = [];
runningTimeout = null;
runningTimeout = undefined;
}, 100);
});
@@ -282,71 +287,29 @@ export class CodeApplication extends Disposable {
//#region Bootstrap IPC Handlers
let slowShellResolveWarningShown = false;
ipcMain.handle('vscode:fetchShellEnv', event => {
return new Promise(async resolve => {
// DO NOT remove: not only usual windows are fetching the
// shell environment but also shared process, issue reporter
// etc, so we need to reply via `webContents` always
const webContents = event.sender;
// Prefer to use the args and env from the target window
// when resolving the shell env. It is possible that
// a first window was opened from the UI but a second
// from the CLI and that has implications for whether to
// resolve the shell environment or not.
//
// Window can be undefined for e.g. the shared process
// that is not part of our windows registry!
const window = this.windowsMainService?.getWindowByWebContents(event.sender); // Note: this can be `undefined` for the shared process
let args: NativeParsedArgs;
let env: IProcessEnvironment;
if (window?.config) {
args = window.config;
env = { ...process.env, ...window.config.userEnv };
} else {
args = this.environmentMainService.args;
env = process.env;
}
let replied = false;
function acceptShellEnv(env: IProcessEnvironment): void {
clearTimeout(shellEnvSlowWarningHandle);
clearTimeout(shellEnvTimeoutErrorHandle);
if (!replied) {
replied = true;
if (!webContents.isDestroyed()) {
resolve(env);
}
}
}
// Handle slow shell environment resolve calls:
// - a warning after 3s but continue to resolve (only once in active window)
// - an error after 10s and stop trying to resolve (in every window where this happens)
const cts = new CancellationTokenSource();
const shellEnvSlowWarningHandle = setTimeout(() => {
if (!slowShellResolveWarningShown) {
this.windowsMainService?.sendToFocused('vscode:showShellEnvSlowWarning', cts.token);
slowShellResolveWarningShown = true;
}
}, 3000);
const window = this.windowsMainService?.getWindowByWebContents(event.sender); // Note: this can be `undefined` for the shared process!!
const shellEnvTimeoutErrorHandle = setTimeout(() => {
cts.dispose(true);
window?.sendWhenReady('vscode:showShellEnvTimeoutError', CancellationToken.None);
acceptShellEnv({});
}, 10000);
// Prefer to use the args and env from the target window
// when resolving the shell env. It is possible that
// a first window was opened from the UI but a second
// from the CLI and that has implications for whether to
// resolve the shell environment or not.
//
// Window can be undefined for e.g. the shared process
// that is not part of our windows registry!
let args: NativeParsedArgs;
let env: IProcessEnvironment;
if (window?.config) {
args = window.config;
env = { ...process.env, ...window.config.userEnv };
} else {
args = this.environmentMainService.args;
env = process.env;
}
// Resolve shell env
const shellEnv = await resolveShellEnv(this.logService, args, env);
acceptShellEnv(shellEnv);
});
// Resolve shell env
return resolveShellEnv(this.logService, args, env);
});
ipcMain.handle('vscode:writeNlsFile', (event, path: unknown, data: unknown) => {
@@ -419,18 +382,6 @@ export class CodeApplication extends Disposable {
this.logService.debug(`from: ${this.environmentMainService.appRoot}`);
this.logService.debug('args:', this.environmentMainService.args);
// TODO@bpasero TODO@deepak1556 workaround for #120655
try {
const cachedDataPath = URI.file(this.environmentMainService.chromeCachedDataDir);
this.logService.trace(`Deleting Chrome cached data path: ${cachedDataPath.fsPath}`);
await this.fileService.del(cachedDataPath, { recursive: true });
} catch (error) {
if ((<FileOperationError>error).fileOperationResult !== FileOperationResult.FILE_NOT_FOUND) {
this.logService.error(error);
}
}
// Make sure we associate the program with the app user model id
// This will help Windows to associate the running program with
// any shortcut that is pinned to the taskbar and prevent showing
@@ -498,11 +449,11 @@ export class CodeApplication extends Disposable {
// We cache the machineId for faster lookups on startup
// and resolve it only once initially if not cached or we need to replace the macOS iBridge device
let machineId = this.stateService.getItem<string>(machineIdKey);
let machineId = this.stateMainService.getItem<string>(machineIdKey);
if (!machineId || (isMacintosh && machineId === '6c9d2bc8f91b89624add29c0abeae7fb42bf539fa1cdb2e3e57cd668fa9bcead')) {
machineId = await getMachineId();
this.stateService.setItem(machineIdKey, machineId);
this.stateMainService.setItem(machineIdKey, machineId);
}
return machineId;
@@ -593,6 +544,15 @@ export class CodeApplication extends Disposable {
// Storage
services.set(IStorageMainService, new SyncDescriptor(StorageMainService));
// External terminal
if (isWindows) {
services.set(IExternalTerminalMainService, new SyncDescriptor(WindowsExternalTerminalService));
} else if (isMacintosh) {
services.set(IExternalTerminalMainService, new SyncDescriptor(MacExternalTerminalService));
} else if (isLinux) {
services.set(IExternalTerminalMainService, new SyncDescriptor(LinuxExternalTerminalService));
}
// Backups
const backupMainService = new BackupMainService(this.environmentMainService, this.configurationService, this.logService);
services.set(IBackupMainService, backupMainService);
@@ -679,6 +639,10 @@ export class CodeApplication extends Disposable {
mainProcessElectronServer.registerChannel('storage', storageChannel);
sharedProcessClient.then(client => client.registerChannel('storage', storageChannel));
// External Terminal
const externalTerminalChannel = ProxyChannel.fromService(accessor.get(IExternalTerminalMainService));
mainProcessElectronServer.registerChannel('externalTerminal', externalTerminalChannel);
// Log Level (main & shared process)
const logLevelChannel = new LogLevelChannel(accessor.get(ILogService));
mainProcessElectronServer.registerChannel('logLevel', logLevelChannel);
@@ -705,16 +669,18 @@ export class CodeApplication extends Disposable {
// Check for initial URLs to handle from protocol link invocations
const pendingWindowOpenablesFromProtocolLinks: IWindowOpenable[] = [];
const pendingProtocolLinksToHandle = [
// Windows/Linux: protocol handler invokes CLI with --open-url
...this.environmentMainService.args['open-url'] ? this.environmentMainService.args._urls || [] : [],
// macOS: open-url events
...((<any>global).getOpenUrls() || []) as string[]
].map(url => {
try {
return { uri: URI.parse(url), url };
} catch {
return null;
return undefined;
}
}).filter((obj): obj is { uri: URI, url: string } => {
if (!obj) {
@@ -744,8 +710,16 @@ export class CodeApplication extends Disposable {
// protocol invocations outside of VSCode.
const app = this;
const environmentService = this.environmentMainService;
const productService = this.productService;
urlService.registerHandler({
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
if (uri.scheme === productService.urlProtocol && uri.path === 'workspace') {
uri = uri.with({
authority: 'file',
path: URI.parse(uri.query).path,
query: ''
});
}
// If URI should be blocked, behave as if it's handled
if (app.shouldBlockURI(uri)) {
@@ -760,7 +734,7 @@ export class CodeApplication extends Disposable {
cli: { ...environmentService.args },
urisToOpen: [windowOpenableFromProtocolLink],
gotoLineMode: true
/* remoteAuthority will be determined based on windowOpenableFromProtocolLink */
// remoteAuthority: will be determined based on windowOpenableFromProtocolLink
});
window.focus(); // this should help ensuring that the right window gets focus when multiple are opened
@@ -823,7 +797,7 @@ export class CodeApplication extends Disposable {
urisToOpen: pendingWindowOpenablesFromProtocolLinks,
gotoLineMode: true,
initialStartup: true
/* remoteAuthority will be determined based on pendingWindowOpenablesFromProtocolLinks */
// remoteAuthority: will be determined based on pendingWindowOpenablesFromProtocolLinks
});
}
@@ -850,7 +824,7 @@ export class CodeApplication extends Disposable {
noRecentEntry,
waitMarkerFileURI,
initialStartup: true,
/* remoteAuthority will be determined based on macOpenFiles */
// remoteAuthority: will be determined based on macOpenFiles
});
}
@@ -957,10 +931,16 @@ export class CodeApplication extends Disposable {
// Logging
let message: string;
if (typeof details === 'string') {
message = details;
} else {
message = `SharedProcess: crashed (detail: ${details.reason})`;
switch (type) {
case WindowError.UNRESPONSIVE:
message = 'SharedProcess: detected unresponsive window';
break;
case WindowError.CRASHED:
message = `SharedProcess: crashed (detail: ${details?.reason ?? '<unknown>'}, code: ${details?.exitCode ?? '<unknown>'})`;
break;
case WindowError.LOAD:
message = `SharedProcess: failed to load (detail: ${details?.reason ?? '<unknown>'}, code: ${details?.exitCode ?? '<unknown>'})`;
break;
}
onUnexpectedError(new Error(message));
@@ -968,18 +948,21 @@ export class CodeApplication extends Disposable {
type SharedProcessErrorClassification = {
type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
reason: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
code: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
visible: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
shuttingdown: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
};
type SharedProcessErrorEvent = {
type: WindowError;
reason: string | undefined;
code: number | undefined;
visible: boolean;
shuttingdown: boolean;
};
telemetryService.publicLog2<SharedProcessErrorEvent, SharedProcessErrorClassification>('sharedprocesserror', {
type,
reason: typeof details !== 'string' ? details?.reason : undefined,
reason: details?.reason,
code: details?.exitCode,
visible: sharedProcess.isVisible(),
shuttingdown: willShutdown
});
@@ -1012,7 +995,16 @@ export class CodeApplication extends Disposable {
}
// Start to fetch shell environment (if needed) after window has opened
resolveShellEnv(this.logService, this.environmentMainService.args, process.env);
// Since this operation can take a long time, we want to warm it up while
// the window is opening.
// We also print a warning if the resolution takes longer than 10s.
(async () => {
const slowResolveShellEnvWarning = this._register(new RunOnceScheduler(() => this.logService.warn('Resolving your shell environment is taking more than 10s. Please review your shell configuration. Learn more at https://go.microsoft.com/fwlink/?linkid=2149667.'), 10000));
slowResolveShellEnvWarning.schedule();
await resolveShellEnv(this.logService, this.environmentMainService.args, process.env);
slowResolveShellEnvWarning.dispose();
})();
// If enable-crash-reporter argv is undefined then this is a fresh start,
// based on telemetry.enableCrashreporter settings, generate a UUID which

View File

@@ -65,7 +65,6 @@ export class ProxyAuthHandler extends Disposable {
private sessionCredentials: Credentials | undefined = undefined;
constructor(
any,
@ILogService private readonly logService: ILogService,
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,

View File

@@ -5,7 +5,8 @@
import 'vs/platform/update/common/update.config.contribution';
import { app, dialog } from 'electron';
import { promises, unlinkSync } from 'fs';
import { unlinkSync } from 'fs';
import { Promises as FSPromises } from 'vs/base/node/pfs';
import { localize } from 'vs/nls';
import { isWindows, IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
import { mark } from 'vs/base/common/performance';
@@ -22,8 +23,8 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ILogService, ConsoleMainLogger, MultiplexLogService, getLogLevel, ILoggerService } from 'vs/platform/log/common/log';
import { StateService } from 'vs/platform/state/node/stateService';
import { IStateService } from 'vs/platform/state/node/state';
import { StateMainService } from 'vs/platform/state/electron-main/stateMainService';
import { IStateMainService } from 'vs/platform/state/electron-main/state';
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
@@ -57,6 +58,7 @@ import { LoggerService } from 'vs/platform/log/node/loggerService';
import { cwd } from 'vs/base/common/process';
import { IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol';
import { ProtocolMainService } from 'vs/platform/protocol/electron-main/protocolMainService';
import { Promises } from 'vs/base/common/async';
/**
* The main VS Code entry point.
@@ -84,17 +86,17 @@ class CodeMain {
setUnexpectedErrorHandler(err => console.error(err));
// Create services
const [instantiationService, instanceEnvironment, environmentService, configurationService, stateService, bufferLogService, productService] = this.createServices();
const [instantiationService, instanceEnvironment, environmentMainService, configurationService, stateMainService, bufferLogService, productService] = this.createServices();
try {
// Init services
try {
await this.initServices(environmentService, configurationService, stateService);
await this.initServices(environmentMainService, configurationService, stateMainService);
} catch (error) {
// Show a dialog for errors that can be resolved by the user
this.handleStartupDataDirError(environmentService, productService.nameLong, error);
this.handleStartupDataDirError(environmentMainService, productService.nameLong, error);
throw error;
}
@@ -108,10 +110,10 @@ class CodeMain {
// Create the main IPC server by trying to be the server
// If this throws an error it means we are not the first
// instance of VS Code running and so we would quit.
const mainProcessNodeIpcServer = await this.claimInstance(logService, environmentService, lifecycleMainService, instantiationService, productService, true);
const mainProcessNodeIpcServer = await this.claimInstance(logService, environmentMainService, lifecycleMainService, instantiationService, productService, true);
// Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906)
bufferLogService.logger = new SpdLogLogger('main', join(environmentService.logsPath, 'main.log'), true, bufferLogService.getLevel());
bufferLogService.logger = new SpdLogLogger('main', join(environmentMainService.logsPath, 'main.log'), true, bufferLogService.getLevel());
// Lifecycle
once(lifecycleMainService.onWillShutdown)(() => {
@@ -126,7 +128,7 @@ class CodeMain {
}
}
private createServices(): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateService, BufferLogService, IProductService] {
private createServices(): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateMainService, BufferLogService, IProductService] {
const services = new ServiceCollection();
// Product
@@ -163,8 +165,8 @@ class CodeMain {
services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService));
// State
const stateService = new StateService(environmentMainService, logService);
services.set(IStateService, stateService);
const stateMainService = new StateMainService(environmentMainService, logService, fileService);
services.set(IStateMainService, stateMainService);
// Request
services.set(IRequestService, new SyncDescriptor(RequestMainService));
@@ -181,7 +183,7 @@ class CodeMain {
// Protocol
services.set(IProtocolMainService, new SyncDescriptor(ProtocolMainService));
return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateService, bufferLogService, productService];
return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateMainService, bufferLogService, productService];
}
private patchEnvironment(environmentMainService: IEnvironmentMainService): IProcessEnvironment {
@@ -201,25 +203,25 @@ class CodeMain {
return instanceEnvironment;
}
private initServices(environmentMainService: IEnvironmentMainService, configurationService: ConfigurationService, stateService: StateService): Promise<unknown> {
private initServices(environmentMainService: IEnvironmentMainService, configurationService: ConfigurationService, stateMainService: StateMainService): Promise<unknown> {
return Promises.settled<unknown>([
// Environment service (paths)
const environmentServiceInitialization = Promise.all<string | undefined>([
environmentMainService.extensionsPath,
environmentMainService.nodeCachedDataDir,
environmentMainService.logsPath,
environmentMainService.globalStorageHome.fsPath,
environmentMainService.workspaceStorageHome.fsPath,
environmentMainService.backupHome
].map(path => path ? promises.mkdir(path, { recursive: true }) : undefined));
// Environment service (paths)
Promise.all<string | undefined>([
environmentMainService.extensionsPath,
environmentMainService.codeCachePath,
environmentMainService.logsPath,
environmentMainService.globalStorageHome.fsPath,
environmentMainService.workspaceStorageHome.fsPath,
environmentMainService.backupHome
].map(path => path ? FSPromises.mkdir(path, { recursive: true }) : undefined)),
// Configuration service
const configurationServiceInitialization = configurationService.initialize();
// Configuration service
configurationService.initialize(),
// State service
const stateServiceInitialization = stateService.init();
return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]);
// State service
stateMainService.init()
]);
}
private async claimInstance(logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise<NodeIPCServer> {

View File

@@ -35,10 +35,7 @@
* forceEnableDeveloperKeybindings?: boolean,
* disallowReloadKeybinding?: boolean,
* removeDeveloperKeybindingsAfterLoad?: boolean
* },
* canModifyDOM?: (config: ISandboxConfiguration) => void,
* beforeLoaderConfig?: (loaderConfig: object) => void,
* beforeRequire?: () => void
* }
* }
* ) => Promise<unknown>
* }}

View File

@@ -11,6 +11,7 @@ import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox/window';
import { $, reset, safeInnerHtml, windowOpenNoOpener } from 'vs/base/browser/dom';
import { Button } from 'vs/base/browser/ui/button/button';
import { Delayer } from 'vs/base/common/async';
import { groupBy } from 'vs/base/common/collections';
import { debounce } from 'vs/base/common/decorators';
import { Disposable } from 'vs/base/common/lifecycle';
@@ -63,6 +64,7 @@ export class IssueReporter extends Disposable {
private receivedPerformanceInfo = false;
private shouldQueueSearch = false;
private hasBeenSubmitted = false;
private delayedSubmit = new Delayer<void>(300);
private readonly previewButton!: Button;
@@ -86,6 +88,7 @@ export class IssueReporter extends Disposable {
const issueReporterElement = this.getElementById('issue-reporter');
if (issueReporterElement) {
this.previewButton = new Button(issueReporterElement);
this.updatePreviewButtonState();
}
const issueTitle = configuration.data.issueTitle;
@@ -138,6 +141,7 @@ export class IssueReporter extends Disposable {
this.applyStyles(configuration.data.styles);
this.handleExtensionData(configuration.data.enabledExtensions);
this.updateExperimentsInfo(configuration.data.experiments);
this.updateRestrictedMode(configuration.data.restrictedMode);
}
render(): void {
@@ -356,7 +360,11 @@ export class IssueReporter extends Disposable {
this.searchIssues(title, fileOnExtension, fileOnMarketplace);
});
this.previewButton.onDidClick(() => this.createIssue());
this.previewButton.onDidClick(async () => {
this.delayedSubmit.trigger(async () => {
this.createIssue();
});
});
function sendWorkbenchCommand(commandId: string) {
ipcRenderer.send('vscode:workbenchCommand', { id: commandId, from: 'issueReporter' });
@@ -383,9 +391,11 @@ export class IssueReporter extends Disposable {
const cmdOrCtrlKey = isMacintosh ? e.metaKey : e.ctrlKey;
// Cmd/Ctrl+Enter previews issue and closes window
if (cmdOrCtrlKey && e.keyCode === 13) {
if (await this.createIssue()) {
ipcRenderer.send('vscode:closeIssueReporter');
}
this.delayedSubmit.trigger(async () => {
if (await this.createIssue()) {
ipcRenderer.send('vscode:closeIssueReporter');
}
});
}
// Cmd/Ctrl + w closes issue window
@@ -1151,6 +1161,10 @@ export class IssueReporter extends Disposable {
}
}
private updateRestrictedMode(restrictedMode: boolean) {
this.issueReporterModel.update({ restrictedMode });
}
private updateExperimentsInfo(experimentInfo: string | undefined) {
this.issueReporterModel.update({ experimentInfo });
const target = document.querySelector<HTMLElement>('.block-experiments .block-info');

View File

@@ -32,6 +32,7 @@ export interface IssueReporterData {
query?: string;
filterResultCount?: number;
experimentInfo?: string;
restrictedMode?: boolean;
}
export class IssueReporterModel {
@@ -68,6 +69,7 @@ ${this._data.issueDescription}
${this.getExtensionVersion()}
Azure Data Studio version: ${this._data.versionInfo && this._data.versionInfo.vscodeVersion}
OS version: ${this._data.versionInfo && this._data.versionInfo.os}
Restricted Mode: ${this._data.restrictedMode ? 'Yes' : 'No'}
${this.getRemoteOSes()}
${this.getInfos()}
<!-- generated by issue reporter -->`;

View File

@@ -33,6 +33,7 @@ undefined
Azure Data Studio version: undefined
OS version: undefined
Restricted Mode: No
Extensions: none
<!-- generated by issue reporter -->`);
@@ -63,6 +64,7 @@ undefined
Azure Data Studio version: undefined
OS version: undefined
Restricted Mode: No
<details>
<summary>System Info</summary>
@@ -106,6 +108,7 @@ undefined
VS Code version: undefined
OS version: undefined
Restricted Mode: No
<details>
<summary>System Info</summary>
@@ -160,6 +163,7 @@ undefined
VS Code version: undefined
OS version: undefined
Restricted Mode: No
<details>
<summary>System Info</summary>
@@ -216,6 +220,7 @@ undefined
VS Code version: undefined
OS version: undefined
Restricted Mode: No
Remote OS version: Linux x64 4.18.0
<details>
@@ -264,6 +269,7 @@ undefined
VS Code version: undefined
OS version: undefined
Restricted Mode: No
<details>
<summary>System Info</summary>

View File

@@ -49,6 +49,10 @@ body {
width: 90px;
}
.monaco-list:focus {
outline: 0;
}
.monaco-list-row:first-of-type {
border-bottom: 1px solid;
}

View File

@@ -32,10 +32,7 @@
* forceEnableDeveloperKeybindings?: boolean,
* disallowReloadKeybinding?: boolean,
* removeDeveloperKeybindingsAfterLoad?: boolean
* },
* canModifyDOM?: (config: ISandboxConfiguration) => void,
* beforeLoaderConfig?: (loaderConfig: object) => void,
* beforeRequire?: () => void
* }
* }
* ) => Promise<unknown>
* }}

View File

@@ -14,13 +14,15 @@ import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
import { popup } from 'vs/base/parts/contextmenu/electron-sandbox/contextmenu';
import { ProcessItem } from 'vs/base/common/processes';
import { append, $ } from 'vs/base/browser/dom';
import { append, $, createStyleSheet } from 'vs/base/browser/dom';
import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { ByteSize } from 'vs/platform/files/common/files';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
import { DataTree } from 'vs/base/browser/ui/tree/dataTree';
import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet';
import { RunOnceScheduler } from 'vs/base/common/async';
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
@@ -310,8 +312,7 @@ class ProcessExplorer {
renderers,
new ProcessTreeDataSource(),
{
identityProvider:
{
identityProvider: {
getId: (element: ProcessTree | ProcessItem | MachineProcessInformation | ProcessInformation | IRemoteDiagnosticError) => {
if (isProcessItem(element)) {
return element.pid.toString();
@@ -331,7 +332,7 @@ class ProcessExplorer {
return 'header';
}
}
},
});
this.tree.setInput({ processes: { processRoots } });
@@ -378,21 +379,45 @@ class ProcessExplorer {
}
private applyStyles(styles: ProcessExplorerStyles): void {
const styleTag = document.createElement('style');
const styleElement = createStyleSheet();
const content: string[] = [];
if (styles.hoverBackground) {
content.push(`.monaco-list-row:hover { background-color: ${styles.hoverBackground}; }`);
if (styles.listFocusBackground) {
content.push(`.monaco-list:focus .monaco-list-row.focused { background-color: ${styles.listFocusBackground}; }`);
content.push(`.monaco-list:focus .monaco-list-row.focused:hover { background-color: ${styles.listFocusBackground}; }`);
}
if (styles.hoverForeground) {
content.push(`.monaco-list-row:hover { color: ${styles.hoverForeground}; }`);
if (styles.listFocusForeground) {
content.push(`.monaco-list:focus .monaco-list-row.focused { color: ${styles.listFocusForeground}; }`);
}
styleTag.textContent = content.join('\n');
if (document.head) {
document.head.appendChild(styleTag);
if (styles.listActiveSelectionBackground) {
content.push(`.monaco-list:focus .monaco-list-row.selected { background-color: ${styles.listActiveSelectionBackground}; }`);
content.push(`.monaco-list:focus .monaco-list-row.selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`);
}
if (styles.listActiveSelectionForeground) {
content.push(`.monaco-list:focus .monaco-list-row.selected { color: ${styles.listActiveSelectionForeground}; }`);
}
if (styles.listHoverBackground) {
content.push(`.monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`);
}
if (styles.listHoverForeground) {
content.push(`.monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`);
}
if (styles.listFocusOutline) {
content.push(`.monaco-list:focus .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }`);
}
if (styles.listHoverOutline) {
content.push(`.monaco-list-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`);
}
styleElement.textContent = content.join('\n');
if (styles.color) {
document.body.style.color = styles.color;
}
@@ -475,9 +500,24 @@ class ProcessExplorer {
}
}
function createCodiconStyleSheet() {
const codiconStyleSheet = createStyleSheet();
codiconStyleSheet.id = 'codiconStyles';
const iconsStyleSheet = getIconsStyleSheet();
function updateAll() {
codiconStyleSheet.textContent = iconsStyleSheet.getCSS();
}
const delayer = new RunOnceScheduler(updateAll, 0);
iconsStyleSheet.onDidChange(() => delayer.schedule());
delayer.schedule();
}
export function startup(configuration: ProcessExplorerWindowConfiguration): void {
const platformClass = configuration.data.platform === 'win32' ? 'windows' : configuration.data.platform === 'linux' ? 'linux' : 'mac';
document.body.classList.add(platformClass); // used by our fonts
createCodiconStyleSheet();
applyZoom(configuration.data.zoomLevel);
new ProcessExplorer(configuration.windowId, configuration.data);

View File

@@ -4,7 +4,7 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote-resource:; media-src 'none'; frame-src 'self' vscode-webview:; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https: ws:; font-src 'self' https: vscode-remote-resource:;">
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types default TrustedFunctionWorkaround ExtensionScripts amdLoader cellRendererEditorText defaultWorkerFactory diffEditorWidget domLineBreaksComputer editorViewLayer diffReview extensionHostWorker insane notebookOutputRenderer safeInnerHtml standaloneColorizer tokenizeToString webNestedWorkerExtensionHost webWorkerExtensionHost;">
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types default TrustedFunctionWorkaround ExtensionScripts amdLoader cellRendererEditorText defaultWorkerFactory diffEditorWidget editorGhostText domLineBreaksComputer editorViewLayer diffReview extensionHostWorker insane notebookRenderer safeInnerHtml standaloneColorizer tokenizeToString webNestedWorkerExtensionHost webWorkerExtensionHost;">
</head>
<body aria-label="">
</body>

View File

@@ -43,7 +43,7 @@
};
},
canModifyDOM: function (windowConfig) {
// TODO@sandbox part-splash is non-sandboxed only
showSplash(windowConfig);
},
beforeLoaderConfig: function (loaderConfig) {
loaderConfig.recordStats = true;
@@ -89,18 +89,20 @@
/**
* @typedef {import('../../../platform/windows/common/windows').INativeWindowConfiguration} INativeWindowConfiguration
* @typedef {import('../../../platform/environment/common/argv').NativeParsedArgs} NativeParsedArgs
*
* @returns {{
* load: (
* modules: string[],
* resultCallback: (result, configuration: INativeWindowConfiguration) => unknown,
* resultCallback: (result, configuration: INativeWindowConfiguration & NativeParsedArgs) => unknown,
* options?: {
* configureDeveloperSettings?: (config: INativeWindowConfiguration & object) => {
* configureDeveloperSettings?: (config: INativeWindowConfiguration & NativeParsedArgs) => {
* forceDisableShowDevtoolsOnError?: boolean,
* forceEnableDeveloperKeybindings?: boolean,
* disallowReloadKeybinding?: boolean,
* removeDeveloperKeybindingsAfterLoad?: boolean
* },
* canModifyDOM?: (config: INativeWindowConfiguration & object) => void,
* canModifyDOM?: (config: INativeWindowConfiguration & NativeParsedArgs) => void,
* beforeLoaderConfig?: (loaderConfig: object) => void,
* beforeRequire?: () => void
* }
@@ -112,5 +114,97 @@
return window.MonacoBootstrapWindow;
}
/**
* @param {INativeWindowConfiguration & NativeParsedArgs} configuration
*/
function showSplash(configuration) {
performance.mark('code/willShowPartsSplash');
let data = configuration.partsSplash;
// high contrast mode has been turned on from the outside, e.g. OS -> ignore stored colors and layouts
const isHighContrast = configuration.colorScheme.highContrast && configuration.autoDetectHighContrast;
if (data && isHighContrast && data.baseTheme !== 'hc-black') {
data = undefined;
}
// developing an extension -> ignore stored layouts
if (data && configuration.extensionDevelopmentPath) {
data.layoutInfo = undefined;
}
// minimal color configuration (works with or without persisted data)
let baseTheme, shellBackground, shellForeground;
if (data) {
baseTheme = data.baseTheme;
shellBackground = data.colorInfo.editorBackground;
shellForeground = data.colorInfo.foreground;
} else if (isHighContrast) {
baseTheme = 'hc-black';
shellBackground = '#000000';
shellForeground = '#FFFFFF';
} else {
baseTheme = 'vs-dark';
shellBackground = '#1E1E1E';
shellForeground = '#CCCCCC';
}
const style = document.createElement('style');
style.className = 'initialShellColors';
document.head.appendChild(style);
style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`;
// restore parts if possible (we might not always store layout info)
if (data?.layoutInfo) {
const { layoutInfo, colorInfo } = data;
const splash = document.createElement('div');
splash.id = 'monaco-parts-splash';
splash.className = baseTheme;
if (layoutInfo.windowBorder) {
splash.style.position = 'relative';
splash.style.height = 'calc(100vh - 2px)';
splash.style.width = 'calc(100vw - 2px)';
splash.style.border = '1px solid var(--window-border-color)';
splash.style.setProperty('--window-border-color', colorInfo.windowBorder);
if (layoutInfo.windowBorderRadius) {
splash.style.borderRadius = layoutInfo.windowBorderRadius;
}
}
// ensure there is enough space
layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth));
// part: title
const titleDiv = document.createElement('div');
titleDiv.setAttribute('style', `position: absolute; width: 100%; left: 0; top: 0; height: ${layoutInfo.titleBarHeight}px; background-color: ${colorInfo.titleBarBackground}; -webkit-app-region: drag;`);
splash.appendChild(titleDiv);
// part: activity bar
const activityDiv = document.createElement('div');
activityDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: 0; width: ${layoutInfo.activityBarWidth}px; background-color: ${colorInfo.activityBarBackground};`);
splash.appendChild(activityDiv);
// part: side bar (only when opening workspace/folder)
// folder or workspace -> status bar color, sidebar
if (configuration.workspace) {
const sideDiv = document.createElement('div');
sideDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; width: ${layoutInfo.sideBarWidth}px; background-color: ${colorInfo.sideBarBackground};`);
splash.appendChild(sideDiv);
}
// part: statusbar
const statusDiv = document.createElement('div');
statusDiv.setAttribute('style', `position: absolute; width: 100%; bottom: 0; left: 0; height: ${layoutInfo.statusBarHeight}px; background-color: ${configuration.workspace ? colorInfo.statusBarBackground : colorInfo.statusBarNoFolderBackground};`);
splash.appendChild(statusDiv);
document.body.appendChild(splash);
}
performance.mark('code/didShowPartsSplash');
}
//#endregion
}());

View File

@@ -13,8 +13,9 @@ import { createWaitMarkerFile } from 'vs/platform/environment/node/wait';
import product from 'vs/platform/product/common/product';
import { isAbsolute, join } from 'vs/base/common/path';
import { whenDeleted, writeFileSync } from 'vs/base/node/pfs';
import { findFreePort, randomPort } from 'vs/base/node/ports';
import { isWindows, isLinux, IProcessEnvironment } from 'vs/base/common/platform';
import { findFreePort } from 'vs/base/node/ports';
import { randomPort } from 'vs/base/common/ports';
import { isWindows, IProcessEnvironment } from 'vs/base/common/platform';
import type { ProfilingSession, Target } from 'v8-inspect-profiler';
import { isString } from 'vs/base/common/types';
import { hasStdinWithoutTty, stdinDataListener, getStdinFilePath, readFromStdin } from 'vs/platform/environment/node/stdin';
@@ -55,7 +56,7 @@ export async function main(argv: string[]): Promise<any> {
// Extensions Management
else if (shouldSpawnCliProcess(args)) {
const cli = await new Promise<IMainCli>((c, e) => require(['vs/code/node/cliProcessMain'], c, e));
const cli = await new Promise<IMainCli>((resolve, reject) => require(['vs/code/node/cliProcessMain'], resolve, reject));
await cli.main(args);
return;
@@ -318,10 +319,6 @@ export async function main(argv: string[]): Promise<any> {
options['stdio'] = 'ignore';
}
if (isLinux) {
addArg(argv, '--no-sandbox'); // Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox
}
const child = spawn(process.execPath, argv.slice(2), options);
if (args.wait && waitMarkerFilePath) {

View File

@@ -6,6 +6,7 @@
import { release, hostname } from 'os';
import * as fs from 'fs';
import { gracefulify } from 'graceful-fs';
import { Promises } from 'vs/base/node/pfs';
import { isAbsolute, join } from 'vs/base/common/path';
import { raceTimeout } from 'vs/base/common/async';
import product from 'vs/platform/product/common/product';
@@ -19,7 +20,7 @@ import { NativeEnvironmentService } from 'vs/platform/environment/node/environme
import { IExtensionManagementService, IExtensionGalleryService, IExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry';
import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties';
@@ -28,8 +29,6 @@ import { RequestService } from 'vs/platform/request/node/requestService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
import { IStateService } from 'vs/platform/state/node/state';
import { StateService } from 'vs/platform/state/node/stateService';
import { ILogService, getLogLevel, LogLevel, ConsoleLogger, MultiplexLogService, ILogger } from 'vs/platform/log/common/log';
import { Schemas } from 'vs/base/common/network';
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
@@ -104,7 +103,7 @@ class CliMain extends Disposable {
services.set(INativeEnvironmentService, environmentService);
// Init folders
await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath].map(path => path ? fs.promises.mkdir(path, { recursive: true }) : undefined));
await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath].map(path => path ? Promises.mkdir(path, { recursive: true }) : undefined));
// Log
const logLevel = getLogLevel(environmentService);
@@ -131,10 +130,6 @@ class CliMain extends Disposable {
// Init config
await configurationService.initialize();
// State
const stateService = new StateService(environmentService, logService);
services.set(IStateService, stateService);
// Request
services.set(IRequestService, new SyncDescriptor(RequestService));
@@ -158,7 +153,19 @@ class CliMain extends Disposable {
const config: ITelemetryServiceConfig = {
appender: combinedAppender(...appenders),
sendErrorTelemetry: false,
commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, stateService.getItem('telemetry.machineId'), productService.msftInternalDomains, installSourcePath),
commonProperties: (async () => {
let machineId: string | undefined = undefined;
try {
const storageContents = await Promises.readFile(join(environmentService.userDataPath, 'storage.json'));
machineId = JSON.parse(storageContents.toString())[machineIdKey];
} catch (error) {
if (error.code !== 'ENOENT') {
logService.error(error);
}
}
return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, productService.msftInternalDomains, installSourcePath);
})(),
piiPaths: [appRoot, extensionsPath]
};
@@ -213,7 +220,7 @@ class CliMain extends Disposable {
// Telemetry
else if (this.argv['telemetry']) {
console.log(buildTelemetryMessage(environmentService.appRoot, environmentService.extensionsPath));
console.log(await buildTelemetryMessage(environmentService.appRoot, environmentService.extensionsPath));
}
}