mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-28 09:35:38 -05:00
Merge from vscode e3c4990c67c40213af168300d1cfeb71d680f877 (#16569)
This commit is contained in:
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,7 @@
|
||||
* forceEnableDeveloperKeybindings?: boolean,
|
||||
* disallowReloadKeybinding?: boolean,
|
||||
* removeDeveloperKeybindingsAfterLoad?: boolean
|
||||
* },
|
||||
* canModifyDOM?: (config: ISandboxConfiguration) => void,
|
||||
* beforeLoaderConfig?: (loaderConfig: object) => void,
|
||||
* beforeRequire?: () => void
|
||||
* }
|
||||
* }
|
||||
* ) => Promise<unknown>
|
||||
* }}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -35,10 +35,7 @@
|
||||
* forceEnableDeveloperKeybindings?: boolean,
|
||||
* disallowReloadKeybinding?: boolean,
|
||||
* removeDeveloperKeybindingsAfterLoad?: boolean
|
||||
* },
|
||||
* canModifyDOM?: (config: ISandboxConfiguration) => void,
|
||||
* beforeLoaderConfig?: (loaderConfig: object) => void,
|
||||
* beforeRequire?: () => void
|
||||
* }
|
||||
* }
|
||||
* ) => Promise<unknown>
|
||||
* }}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 -->`;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -49,6 +49,10 @@ body {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.monaco-list:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.monaco-list-row:first-of-type {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
@@ -32,10 +32,7 @@
|
||||
* forceEnableDeveloperKeybindings?: boolean,
|
||||
* disallowReloadKeybinding?: boolean,
|
||||
* removeDeveloperKeybindingsAfterLoad?: boolean
|
||||
* },
|
||||
* canModifyDOM?: (config: ISandboxConfiguration) => void,
|
||||
* beforeLoaderConfig?: (loaderConfig: object) => void,
|
||||
* beforeRequire?: () => void
|
||||
* }
|
||||
* }
|
||||
* ) => Promise<unknown>
|
||||
* }}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user