Archived
1
0

chore(vscode): update to 1.55.2

This commit is contained in:
Akash Satheesan
2021-04-09 11:32:27 +05:30
1102 changed files with 39988 additions and 23544 deletions

View File

@ -0,0 +1,80 @@
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html>
<head>
<script>
performance.mark('code/didStartRenderer')
</script>
<meta charset="utf-8" />
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<!-- Workbench Configuration -->
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONFIGURATION}}">
<!-- Workbench Auth Session -->
<meta id="vscode-workbench-auth-session" data-settings="{{WORKBENCH_AUTH_SESSION}}">
<!-- Workbench Icon/Manifest/CSS -->
<link rel="icon" href="{{WORKBENCH_WEB_BASE_URL}}/favicon.ico" type="image/x-icon" />
<link rel="manifest" href="{{WORKBENCH_WEB_BASE_URL}}/manifest.json">
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/workbench/workbench.web.api.css">
</head>
<body aria-label="">
</body>
<!-- Startup (do not modify order of script tags!) -->
<script>
var baseUrl = '{{WORKBENCH_WEB_BASE_URL}}';
self.require = {
baseUrl: `${baseUrl}/out`,
recordStats: true,
trustedTypesPolicy: window.trustedTypes?.createPolicy('amdLoader', {
createScriptURL(value) {
if(value.startsWith(baseUrl)) {
return value;
}
throw new Error(`Invalid script url: ${value}`)
}
}),
paths: {
'vscode-textmate': `${baseUrl}/node_modules/vscode-textmate/release/main`,
'vscode-oniguruma': `${baseUrl}/node_modules/vscode-oniguruma/release/main`,
'xterm': `${baseUrl}/node_modules/xterm/lib/xterm.js`,
'xterm-addon-search': `${baseUrl}/node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
'xterm-addon-unicode11': `${baseUrl}/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
'xterm-addon-webgl': `${baseUrl}/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
'tas-client-umd': `${baseUrl}/node_modules/tas-client-umd/lib/tas-client-umd.js`,
'iconv-lite-umd': `${baseUrl}/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
'jschardet': `${baseUrl}/node_modules/jschardet/dist/jschardet.min.js`,
}
};
</script>
<script src="{{WORKBENCH_WEB_BASE_URL}}/out/vs/loader.js"></script>
<script>
performance.mark('code/willLoadWorkbenchMain');
</script>
<script>
if ("{{WORKBENCH_DEV}}" === "true") {
const workbench = document.createElement('script');
workbench.innerText = "require(['vs/code/browser/workbench/workbench'], function() {});";
document.body.appendChild(workbench);
} else {
const nls = document.createElement('script');
nls.setAttribute('src', '{{WORKBENCH_WEB_BASE_URL}}/out/vs/workbench/workbench.web.api.nls.js');
document.body.appendChild(nls);
const api = document.createElement('script');
api.setAttribute('src', '{{WORKBENCH_WEB_BASE_URL}}/out/vs/workbench/workbench.web.api.js');
document.body.appendChild(api);
const workbench = document.createElement('script');
workbench.setAttribute('src', '{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.js');
document.body.appendChild(workbench);
}
</script>
</html>

View File

@ -7,7 +7,7 @@ import * as fs from 'fs';
import * as path from 'vs/base/common/path';
import * as pfs from 'vs/base/node/pfs';
import { IStringDictionary } from 'vs/base/common/collections';
import product from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ILogService } from 'vs/platform/log/common/log';
@ -32,9 +32,14 @@ interface LanguagePackFile {
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
constructor(
@INativeEnvironmentService private readonly _environmentService: INativeEnvironmentService,
@ILogService private readonly _logService: ILogService
@ILogService private readonly _logService: ILogService,
@IProductService private readonly _productService: IProductService
) {
super();
// We have no Language pack support for dev version (run from source)
@ -48,9 +53,6 @@ export class LanguagePackCachedDataCleaner extends Disposable {
let handle: any = setTimeout(async () => {
handle = undefined;
this._logService.info('Starting to clean up unused language packs.');
const maxAge = product.nameLong.indexOf('Insiders') >= 0
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months
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'));
@ -84,7 +86,7 @@ export class LanguagePackCachedDataCleaner extends Disposable {
const stat = await fs.promises.stat(candidate);
if (stat.isDirectory()) {
const diff = now - stat.mtime.getTime();
if (diff > maxAge) {
if (diff > this._DataMaxAge) {
this._logService.info('Removing language pack cache entry: ', path.join(packEntry, entry));
await pfs.rimraf(candidate);
}

View File

@ -8,18 +8,19 @@ 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 product from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
export class NodeCachedDataCleaner {
private static readonly _DataMaxAge = product.nameLong.indexOf('Insiders') >= 0
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
private readonly nodeCachedDataDir: string | undefined,
@IProductService private readonly productService: IProductService
) {
this._manageCachedDataSoon();
}
@ -61,7 +62,7 @@ export class NodeCachedDataCleaner {
// * only when old enough
if (stats.isDirectory()) {
const diff = now - stats.mtime.getTime();
if (diff > NodeCachedDataCleaner._DataMaxAge) {
if (diff > this._DataMaxAge) {
return rimraf(path);
}
}

View File

@ -13,7 +13,7 @@ import { StaticRouter, ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
import { ExtensionManagementChannel, ExtensionTipsChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
import { IRequestService } from 'vs/platform/request/common/request';
import { RequestService } from 'vs/platform/request/browser/requestService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ICustomEndpointTelemetryService, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { combinedAppender, NullTelemetryService, ITelemetryAppender, NullAppender } from 'vs/platform/telemetry/common/telemetryUtils';
import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties';
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc';
@ -58,7 +58,7 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { LoggerService } from 'vs/platform/log/node/loggerService';
import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog';
import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService';
import { NativeStorageService2 } from 'vs/platform/storage/electron-sandbox/storageService2';
import { NativeStorageService } from 'vs/platform/storage/electron-sandbox/storageService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
import { UserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/common/userDataSyncResourceEnablementService';
@ -81,9 +81,12 @@ import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/err
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { join } from 'vs/base/common/path';
import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal';
import { LocalPtyService } from 'vs/platform/terminal/electron-browser/localPtyService';
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';
import { IChecksumService } from 'vs/platform/checksum/common/checksumService';
import { ChecksumService } from 'vs/platform/checksum/node/checksumService';
import { CustomEndpointTelemetryService } from 'vs/platform/telemetry/node/customEndpointTelemetryService';
class SharedProcessMain extends Disposable {
@ -129,7 +132,7 @@ class SharedProcessMain extends Disposable {
// Instantiate Contributions
this._register(combinedDisposable(
new NodeCachedDataCleaner(this.configuration.nodeCachedDataDir),
instantiationService.createInstance(NodeCachedDataCleaner, this.configuration.nodeCachedDataDir),
instantiationService.createInstance(LanguagePackCachedDataCleaner),
instantiationService.createInstance(StorageDataCleaner, this.configuration.backupWorkspacesPath),
instantiationService.createInstance(LogsDataCleaner),
@ -141,9 +144,12 @@ class SharedProcessMain extends Disposable {
private async initServices(): Promise<IInstantiationService> {
const services = new ServiceCollection();
// Product
const productService = { _serviceBrand: undefined, ...product };
services.set(IProductService, productService);
// Environment
const environmentService = new NativeEnvironmentService(this.configuration.args);
services.set(IEnvironmentService, environmentService);
const environmentService = new NativeEnvironmentService(this.configuration.args, productService);
services.set(INativeEnvironmentService, environmentService);
// Log
@ -175,18 +181,18 @@ class SharedProcessMain extends Disposable {
await configurationService.initialize();
// Storage (global access only)
const storageService = new NativeStorageService2(undefined, mainProcessService, environmentService);
const storageService = new NativeStorageService(undefined, mainProcessService, environmentService);
services.set(IStorageService, storageService);
await storageService.initialize();
this._register(toDisposable(() => storageService.flush()));
// Product
services.set(IProductService, { _serviceBrand: undefined, ...product });
// Request
services.set(IRequestService, new SyncDescriptor(RequestService));
// Checksum
services.set(IChecksumService, new SyncDescriptor(ChecksumService));
// Native Host
const nativeHostService = ProxyChannel.toService<INativeHostService>(mainProcessService.getChannel('nativeHost'), { context: this.configuration.windowId });
services.set(INativeHostService, nativeHostService);
@ -208,19 +214,19 @@ class SharedProcessMain extends Disposable {
let telemetryService: ITelemetryService;
let telemetryAppender: ITelemetryAppender;
if (!extensionDevelopmentLocationURI && !environmentService.disableTelemetry && product.enableTelemetry) {
if (!extensionDevelopmentLocationURI && !environmentService.disableTelemetry && productService.enableTelemetry) {
telemetryAppender = new TelemetryLogAppender(loggerService, environmentService);
// Application Insights
if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) {
const appInsightsAppender = new AppInsightsAppender('monacoworkbench', null, product.aiConfig.asimovKey);
if (productService.aiConfig && productService.aiConfig.asimovKey && isBuilt) {
const appInsightsAppender = new AppInsightsAppender('monacoworkbench', null, productService.aiConfig.asimovKey);
this._register(toDisposable(() => appInsightsAppender.flush())); // Ensure the AI appender is disposed so that it flushes remaining data
telemetryAppender = combinedAppender(appInsightsAppender, telemetryAppender);
}
telemetryService = new TelemetryService({
appender: telemetryAppender,
commonProperties: resolveCommonProperties(fileService, release(), process.arch, product.commit, product.version, this.configuration.machineId, product.msftInternalDomains, installSourcePath),
commonProperties: resolveCommonProperties(fileService, release(), process.arch, productService.commit, productService.version, this.configuration.machineId, productService.msftInternalDomains, installSourcePath),
sendErrorTelemetry: true,
piiPaths: [appRoot, extensionsPath]
}, configurationService);
@ -232,6 +238,10 @@ class SharedProcessMain extends Disposable {
this.server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(telemetryAppender));
services.set(ITelemetryService, telemetryService);
// Custom Endpoint Telemetry
const customEndpointTelemetryService = new CustomEndpointTelemetryService(configurationService, telemetryService);
services.set(ICustomEndpointTelemetryService, customEndpointTelemetryService);
// Extension Management
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
@ -263,8 +273,7 @@ class SharedProcessMain extends Disposable {
services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService));
// Terminal
const localPtyService = this._register(new LocalPtyService(logService));
services.set(ILocalPtyService, localPtyService);
services.set(ILocalPtyService, this._register(new PtyHostService(logService)));
return new InstantiationService(services);
}
@ -287,10 +296,18 @@ class SharedProcessMain extends Disposable {
const extensionTipsChannel = new ExtensionTipsChannel(accessor.get(IExtensionTipsService));
this.server.registerChannel('extensionTipsService', extensionTipsChannel);
// Checksum
const checksumChannel = ProxyChannel.fromService(accessor.get(IChecksumService));
this.server.registerChannel('checksum', checksumChannel);
// Settings Sync
const userDataSyncMachineChannel = new UserDataSyncMachinesServiceChannel(accessor.get(IUserDataSyncMachinesService));
this.server.registerChannel('userDataSyncMachines', userDataSyncMachineChannel);
// Custom Endpoint Telemetry
const customEndpointTelemetryChannel = ProxyChannel.fromService(accessor.get(ICustomEndpointTelemetryService));
this.server.registerChannel('customEndpointTelemetry', customEndpointTelemetryChannel);
const userDataSyncAccountChannel = new UserDataSyncAccountServiceChannel(accessor.get(IUserDataSyncAccountService));
this.server.registerChannel('userDataSyncAccount', userDataSyncAccountChannel);

View File

@ -33,7 +33,7 @@ import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtil
import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties';
import product from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { ProxyAuthHandler } from 'vs/code/electron-main/auth';
import { FileProtocolHandler } from 'vs/code/electron-main/protocol';
import { Disposable } from 'vs/base/common/lifecycle';
@ -80,13 +80,14 @@ import { EncryptionMainService, IEncryptionMainService } from 'vs/platform/encry
import { ActiveWindowManager } from 'vs/platform/windows/node/windowTracker';
import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService';
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { DisplayMainService, IDisplayMainService } from 'vs/platform/display/electron-main/displayMainService';
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
import { isEqualOrParent } from 'vs/base/common/extpath';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
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';
/**
* The main VS Code application. There will only ever be one instance,
@ -105,7 +106,8 @@ export class CodeApplication extends Disposable {
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IStateService private readonly stateService: IStateService,
@IFileService private readonly fileService: IFileService
@IFileService private readonly fileService: IFileService,
@IProductService private readonly productService: IProductService
) {
super();
@ -418,7 +420,7 @@ export class CodeApplication extends Disposable {
// This will help Windows to associate the running program with
// any shortcut that is pinned to the taskbar and prevent showing
// two icons in the taskbar for the same app.
const win32AppUserModelId = product.win32AppUserModelId;
const win32AppUserModelId = this.productService.win32AppUserModelId;
if (isWindows && win32AppUserModelId) {
app.setAppUserModelId(win32AppUserModelId);
}
@ -559,9 +561,6 @@ export class CodeApplication extends Disposable {
// Keyboard Layout
services.set(IKeyboardLayoutMainService, new SyncDescriptor(KeyboardLayoutMainService));
// Display
services.set(IDisplayMainService, new SyncDescriptor(DisplayMainService));
// Native Host
services.set(INativeHostMainService, new SyncDescriptor(NativeHostMainService, [sharedProcess]));
@ -590,10 +589,10 @@ export class CodeApplication extends Disposable {
services.set(IURLService, new SyncDescriptor(NativeURLService));
// Telemetry
if (!this.environmentMainService.isExtensionDevelopment && !this.environmentMainService.args['disable-telemetry'] && !!product.enableTelemetry) {
if (!this.environmentMainService.isExtensionDevelopment && !this.environmentMainService.args['disable-telemetry'] && !!this.productService.enableTelemetry) {
const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender')));
const appender = new TelemetryAppenderClient(channel);
const commonProperties = resolveCommonProperties(this.fileService, release(), process.arch, product.commit, product.version, machineId, product.msftInternalDomains, this.environmentMainService.installSourcePath);
const commonProperties = resolveCommonProperties(this.fileService, release(), process.arch, this.productService.commit, this.productService.version, machineId, this.productService.msftInternalDomains, this.environmentMainService.installSourcePath);
const piiPaths = [this.environmentMainService.appRoot, this.environmentMainService.extensionsPath];
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, sendErrorTelemetry: true };
@ -629,14 +628,14 @@ export class CodeApplication extends Disposable {
const encryptionChannel = ProxyChannel.fromService(accessor.get(IEncryptionMainService));
mainProcessElectronServer.registerChannel('encryption', encryptionChannel);
// Signing
const signChannel = ProxyChannel.fromService(accessor.get(ISignService));
mainProcessElectronServer.registerChannel('sign', signChannel);
// Keyboard Layout
const keyboardLayoutChannel = ProxyChannel.fromService(accessor.get(IKeyboardLayoutMainService));
mainProcessElectronServer.registerChannel('keyboardLayout', keyboardLayoutChannel);
// Display
const displayChannel = ProxyChannel.fromService(accessor.get(IDisplayMainService));
mainProcessElectronServer.registerChannel('display', displayChannel);
// Native host (main & shared process)
this.nativeHostMainService = accessor.get(INativeHostMainService);
const nativeHostChannel = ProxyChannel.fromService(this.nativeHostMainService);
@ -751,6 +750,7 @@ export class CodeApplication extends Disposable {
cli: { ...environmentService.args },
urisToOpen: [windowOpenableFromProtocolLink],
gotoLineMode: true
/* remoteAuthority will be determined based on windowOpenableFromProtocolLink */
});
window.focus(); // this should help ensuring that the right window gets focus when multiple are opened
@ -765,7 +765,8 @@ export class CodeApplication extends Disposable {
context: OpenContext.API,
cli: { ...environmentService.args },
forceEmpty: true,
gotoLineMode: true
gotoLineMode: true,
remoteAuthority: getRemoteAuthority(uri)
});
await window.ready();
@ -789,7 +790,7 @@ export class CodeApplication extends Disposable {
urlService.registerHandler(new URLHandlerChannelClient(urlHandlerChannel));
// Watch Electron URLs and forward them to the UrlService
this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentMainService));
this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentMainService, this.productService));
// Open our first window
const args = this.environmentMainService.args;
@ -800,6 +801,7 @@ export class CodeApplication extends Disposable {
const hasFileURIs = !!args['file-uri'];
const noRecentEntry = args['skip-add-to-recently-opened'] === true;
const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined;
const remoteAuthority = args.remote || undefined;
// check for a pending window to open from URI
// e.g. when running code with --open-uri from
@ -811,6 +813,7 @@ export class CodeApplication extends Disposable {
urisToOpen: pendingWindowOpenablesFromProtocolLinks,
gotoLineMode: true,
initialStartup: true
/* remoteAuthority will be determined based on pendingWindowOpenablesFromProtocolLinks */
});
}
@ -823,7 +826,8 @@ export class CodeApplication extends Disposable {
forceEmpty: true,
noRecentEntry,
waitMarkerFileURI,
initialStartup: true
initialStartup: true,
remoteAuthority
});
}
@ -835,7 +839,8 @@ export class CodeApplication extends Disposable {
urisToOpen: macOpenFiles.map(file => this.getWindowOpenableFromPathSync(file)),
noRecentEntry,
waitMarkerFileURI,
initialStartup: true
initialStartup: true,
/* remoteAuthority will be determined based on macOpenFiles */
});
}
@ -848,21 +853,22 @@ export class CodeApplication extends Disposable {
noRecentEntry,
waitMarkerFileURI,
gotoLineMode: args.goto,
initialStartup: true
initialStartup: true,
remoteAuthority
});
}
private shouldBlockURI(uri: URI): boolean {
if (uri.authority === Schemas.file && isWindows) {
const res = dialog.showMessageBoxSync({
title: product.nameLong,
title: this.productService.nameLong,
type: 'question',
buttons: [
mnemonicButtonLabel(localize({ key: 'open', comment: ['&& denotes a mnemonic'] }, "&&Yes")),
mnemonicButtonLabel(localize({ key: 'cancel', comment: ['&& denotes a mnemonic'] }, "&&No")),
],
cancelId: 1,
message: localize('confirmOpenMessage', "An external application wants to open '{0}' in {1}. Do you want to open this file or folder?", getPathLabel(uri.fsPath, this.environmentMainService), product.nameShort),
message: localize('confirmOpenMessage', "An external application wants to open '{0}' in {1}. Do you want to open this file or folder?", getPathLabel(uri.fsPath, this.environmentMainService), this.productService.nameShort),
detail: localize('confirmOpenDetail', "If you did not initiate this request, it may represent an attempted attack on your system. Unless you took an explicit action to initiate this request, you should press 'No'"),
noLink: true
});
@ -948,16 +954,22 @@ export class CodeApplication extends Disposable {
type SharedProcessErrorClassification = {
type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
reason: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
visible: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
};
type SharedProcessErrorEvent = {
type: WindowError;
reason: string | undefined;
visible: boolean;
};
telemetryService.publicLog2<SharedProcessErrorEvent, SharedProcessErrorClassification>('sharedprocesserror', { type, reason: typeof details !== 'string' ? details.reason : undefined });
telemetryService.publicLog2<SharedProcessErrorEvent, SharedProcessErrorClassification>('sharedprocesserror', {
type,
reason: typeof details !== 'string' ? details?.reason : undefined,
visible: sharedProcess.isVisible()
});
}));
// Windows: install mutex
const win32MutexName = product.win32MutexName;
const win32MutexName = this.productService.win32MutexName;
if (isWindows && win32MutexName) {
try {
const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex;
@ -1027,7 +1039,7 @@ export class CodeApplication extends Disposable {
recordingStopped = true; // only once
const path = await contentTracing.stopRecording(joinPath(this.environmentMainService.userHome, `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`).fsPath);
const path = await contentTracing.stopRecording(joinPath(this.environmentMainService.userHome, `${this.productService.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`).fsPath);
if (!timeout) {
dialogMainService.showMessageBox({

View File

@ -12,7 +12,7 @@ import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
import { IEncryptionMainService } from 'vs/platform/encryption/electron-main/encryptionMainService';
import { generateUuid } from 'vs/base/common/uuid';
import product from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { CancellationToken } from 'vs/base/common/cancellation';
interface ElectronAuthenticationResponseDetails extends AuthenticationResponseDetails {
@ -56,7 +56,7 @@ enum ProxyAuthState {
export class ProxyAuthHandler extends Disposable {
private static PROXY_CREDENTIALS_SERVICE_KEY = `${product.urlProtocol}.proxy-credentials`;
private readonly PROXY_CREDENTIALS_SERVICE_KEY = `${this.productService.urlProtocol}.proxy-credentials`;
private pendingProxyResolve: Promise<Credentials | undefined> | undefined = undefined;
@ -68,7 +68,8 @@ export class ProxyAuthHandler extends Disposable {
@ILogService private readonly logService: ILogService,
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
@IEncryptionMainService private readonly encryptionMainService: IEncryptionMainService
@IEncryptionMainService private readonly encryptionMainService: IEncryptionMainService,
@IProductService private readonly productService: IProductService
) {
super();
@ -153,7 +154,7 @@ export class ProxyAuthHandler extends Disposable {
let storedUsername: string | undefined = undefined;
let storedPassword: string | undefined = undefined;
try {
const encryptedSerializedProxyCredentials = await this.nativeHostMainService.getPassword(undefined, ProxyAuthHandler.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
const encryptedSerializedProxyCredentials = await this.nativeHostMainService.getPassword(undefined, this.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
if (encryptedSerializedProxyCredentials) {
const credentials: Credentials = JSON.parse(await this.encryptionMainService.decrypt(encryptedSerializedProxyCredentials));
@ -211,9 +212,9 @@ export class ProxyAuthHandler extends Disposable {
try {
if (reply.remember) {
const encryptedSerializedCredentials = await this.encryptionMainService.encrypt(JSON.stringify(credentials));
await this.nativeHostMainService.setPassword(undefined, ProxyAuthHandler.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash, encryptedSerializedCredentials);
await this.nativeHostMainService.setPassword(undefined, this.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash, encryptedSerializedCredentials);
} else {
await this.nativeHostMainService.deletePassword(undefined, ProxyAuthHandler.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
await this.nativeHostMainService.deletePassword(undefined, this.PROXY_CREDENTIALS_SERVICE_KEY, authInfoHash);
}
} catch (error) {
this.logService.error(error); // handle gracefully

View File

@ -23,7 +23,6 @@ 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 { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
@ -54,6 +53,7 @@ import { EnvironmentMainService, IEnvironmentMainService } from 'vs/platform/env
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { LoggerService } from 'vs/platform/log/node/loggerService';
import { cwd } from 'vs/base/common/process';
/**
* The main VS Code entry point.
@ -84,7 +84,7 @@ class CodeMain {
const args = this.resolveArgs();
// Create services
const [instantiationService, instanceEnvironment, environmentService, configurationService, stateService, bufferLogService] = this.createServices(args);
const [instantiationService, instanceEnvironment, environmentService, configurationService, stateService, bufferLogService, productService] = this.createServices(args);
try {
@ -94,7 +94,7 @@ class CodeMain {
} catch (error) {
// Show a dialog for errors that can be resolved by the user
this.handleStartupDataDirError(environmentService, error);
this.handleStartupDataDirError(environmentService, productService.nameLong, error);
throw error;
}
@ -108,7 +108,7 @@ 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.doStartup(args, logService, environmentService, lifecycleMainService, instantiationService, true);
const mainProcessNodeIpcServer = await this.doStartup(args, logService, environmentService, 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());
@ -126,20 +126,23 @@ class CodeMain {
}
}
private createServices(args: NativeParsedArgs): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateService, BufferLogService] {
private createServices(args: NativeParsedArgs): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateService, BufferLogService, IProductService] {
const services = new ServiceCollection();
// Product
const productService = { _serviceBrand: undefined, ...product };
services.set(IProductService, productService);
// Environment
const environmentService = new EnvironmentMainService(args);
const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment
services.set(IEnvironmentService, environmentService);
services.set(IEnvironmentMainService, environmentService);
const environmentMainService = new EnvironmentMainService(args, productService);
const instanceEnvironment = this.patchEnvironment(environmentMainService); // Patch `process.env` with the instance's environment
services.set(IEnvironmentMainService, environmentMainService);
// Log: We need to buffer the spdlog logs until we are sure
// we are the only instance running, otherwise we'll have concurrent
// log file access on Windows (https://github.com/microsoft/vscode/issues/41218)
const bufferLogService = new BufferLogService();
const logService = new MultiplexLogService([new ConsoleMainLogger(getLogLevel(environmentService)), bufferLogService]);
const logService = new MultiplexLogService([new ConsoleMainLogger(getLogLevel(environmentMainService)), bufferLogService]);
process.once('exit', () => logService.dispose());
services.set(ILogService, logService);
@ -153,14 +156,14 @@ class CodeMain {
services.set(ILoggerService, new LoggerService(logService, fileService));
// Configuration
const configurationService = new ConfigurationService(environmentService.settingsResource, fileService);
const configurationService = new ConfigurationService(environmentMainService.settingsResource, fileService);
services.set(IConfigurationService, configurationService);
// Lifecycle
services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService));
// State
const stateService = new StateService(environmentService, logService);
const stateService = new StateService(environmentMainService, logService);
services.set(IStateService, stateService);
// Request
@ -172,13 +175,10 @@ class CodeMain {
// Signing
services.set(ISignService, new SyncDescriptor(SignService));
// Product
services.set(IProductService, { _serviceBrand: undefined, ...product });
// Tunnel
services.set(ITunnelService, new SyncDescriptor(TunnelService));
return [new InstantiationService(services, true), instanceEnvironment, environmentService, configurationService, stateService, bufferLogService];
return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateService, bufferLogService, productService];
}
private patchEnvironment(environmentMainService: IEnvironmentMainService): IProcessEnvironment {
@ -219,7 +219,7 @@ class CodeMain {
return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]);
}
private async doStartup(args: NativeParsedArgs, logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, retry: boolean): Promise<NodeIPCServer> {
private async doStartup(args: NativeParsedArgs, logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise<NodeIPCServer> {
// Try to setup a server for running. If that succeeds it means
// we are the first instance to startup. Otherwise it is likely
@ -235,7 +235,7 @@ class CodeMain {
if (error.code !== 'EADDRINUSE') {
// Show a dialog for errors that can be resolved by the user
this.handleStartupDataDirError(environmentMainService, error);
this.handleStartupDataDirError(environmentMainService, productService.nameLong, error);
// Any other runtime error is just printed to the console
throw error;
@ -251,8 +251,9 @@ class CodeMain {
if (!retry || isWindows || error.code !== 'ECONNREFUSED') {
if (error.code === 'EPERM') {
this.showStartupWarningDialog(
localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort),
localize('secondInstanceAdminDetail', "Please close the other instance and try again.")
localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", productService.nameShort),
localize('secondInstanceAdminDetail', "Please close the other instance and try again."),
productService.nameLong
);
}
@ -270,7 +271,7 @@ class CodeMain {
throw error;
}
return this.doStartup(args, logService, environmentMainService, lifecycleMainService, instantiationService, false);
return this.doStartup(args, logService, environmentMainService, lifecycleMainService, instantiationService, productService, false);
}
// Tests from CLI require to be the only instance currently
@ -289,8 +290,9 @@ class CodeMain {
if (!args.wait && !args.status) {
startupWarningDialogHandle = setTimeout(() => {
this.showStartupWarningDialog(
localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort),
localize('secondInstanceNoResponseDetail', "Please close all other instances and try again.")
localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", productService.nameShort),
localize('secondInstanceNoResponseDetail', "Please close all other instances and try again."),
productService.nameLong
);
}, 10000);
}
@ -300,7 +302,7 @@ class CodeMain {
// Process Info
if (args.status) {
return instantiationService.invokeFunction(async () => {
const diagnosticsService = new DiagnosticsService(NullTelemetryService);
const diagnosticsService = new DiagnosticsService(NullTelemetryService, productService);
const mainProcessInfo = await launchService.getMainProcessInfo();
const remoteDiagnostics = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
const diagnostics = await diagnosticsService.getDiagnostics(mainProcessInfo, remoteDiagnostics);
@ -344,23 +346,24 @@ class CodeMain {
return mainProcessNodeIpcServer;
}
private handleStartupDataDirError(environmentMainService: IEnvironmentMainService, error: NodeJS.ErrnoException): void {
private handleStartupDataDirError(environmentMainService: IEnvironmentMainService, title: string, error: NodeJS.ErrnoException): void {
if (error.code === 'EACCES' || error.code === 'EPERM') {
const directories = coalesce([environmentMainService.userDataPath, environmentMainService.extensionsPath, XDG_RUNTIME_DIR]).map(folder => getPathLabel(folder, environmentMainService));
this.showStartupWarningDialog(
localize('startupDataDirError', "Unable to write program user data."),
localize('startupUserDataAndExtensionsDirErrorDetail', "{0}\n\nPlease make sure the following directories are writeable:\n\n{1}", toErrorMessage(error), directories.join('\n'))
localize('startupUserDataAndExtensionsDirErrorDetail', "{0}\n\nPlease make sure the following directories are writeable:\n\n{1}", toErrorMessage(error), directories.join('\n')),
title
);
}
}
private showStartupWarningDialog(message: string, detail: string): void {
private showStartupWarningDialog(message: string, detail: string, title: string): void {
// use sync variant here because we likely exit after this method
// due to startup issues and otherwise the dialog seems to disappear
// https://github.com/microsoft/vscode/issues/104493
dialog.showMessageBoxSync({
title: product.nameLong,
title,
type: 'warning',
buttons: [mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
message,
@ -451,7 +454,7 @@ class CodeMain {
}
private doValidatePaths(args: string[], gotoLineMode?: boolean): string[] {
const cwd = process.env['VSCODE_CWD'] || process.cwd();
const currentWorkingDir = cwd();
const result = args.map(arg => {
let pathCandidate = String(arg);
@ -462,10 +465,10 @@ class CodeMain {
}
if (pathCandidate) {
pathCandidate = this.preparePath(cwd, pathCandidate);
pathCandidate = this.preparePath(currentWorkingDir, pathCandidate);
}
const sanitizedFilePath = sanitizeFilePath(pathCandidate, cwd);
const sanitizedFilePath = sanitizeFilePath(pathCandidate, currentWorkingDir);
const filePathBasename = basename(sanitizedFilePath);
if (filePathBasename /* can be empty if code is opened on root */ && !isValidBasename(filePathBasename)) {

View File

@ -13,12 +13,14 @@ import { ILogService } from 'vs/platform/log/common/log';
import { TernarySearchTree } from 'vs/base/common/map';
import { isLinux, isPreferringBrowserCodeLoad } from 'vs/base/common/platform';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { extname } from 'vs/base/common/resources';
type ProtocolCallback = { (result: string | Electron.FilePathWithHeaders | { error: number }): void };
export class FileProtocolHandler extends Disposable {
private readonly validRoots = TernarySearchTree.forUris<boolean>(() => !isLinux);
private readonly validExtensions = new Set(['.png', '.jpg', '.jpeg', '.gif', '.bmp']); // https://github.com/microsoft/vscode/issues/119384
constructor(
@INativeEnvironmentService environmentService: INativeEnvironmentService,
@ -85,14 +87,23 @@ export class FileProtocolHandler extends Disposable {
const fileUri = URI.parse(request.url);
// isPreferringBrowserCodeLoad: false
// => ensure the file path is in our expected roots
if (!isPreferringBrowserCodeLoad) {
// first check by validRoots
if (this.validRoots.findSubstr(fileUri)) {
return callback({
path: fileUri.fsPath
});
}
// then check by validExtensions
if (this.validExtensions.has(extname(fileUri))) {
return callback({
path: fileUri.fsPath
});
}
// finally block to load the resource
this.logService.error(`${Schemas.file}: Refused to load resource ${fileUri.fsPath} from ${Schemas.file}: protocol (original URL: ${request.url})`);
return callback({ error: -3 /* ABORTED */ });
@ -114,14 +125,24 @@ export class FileProtocolHandler extends Disposable {
// ensure the root is valid and properly tell Chrome where the
// resource is at.
const fileUri = FileAccess.asFileUri(uri);
// first check by validRoots
if (this.validRoots.findSubstr(fileUri)) {
return callback({
path: fileUri.fsPath
});
} else {
this.logService.error(`${Schemas.vscodeFileResource}: Refused to load resource ${fileUri.fsPath} from ${Schemas.vscodeFileResource}: protocol (original URL: ${request.url})`);
return callback({ error: -3 /* ABORTED */ });
}
// then check by validExtensions
if (this.validExtensions.has(extname(fileUri))) {
return callback({
path: fileUri.fsPath
});
}
// finally block to load the resource
this.logService.error(`${Schemas.vscodeFileResource}: Refused to load resource ${fileUri.fsPath} from ${Schemas.vscodeFileResource}: protocol (original URL: ${request.url})`);
return callback({ error: -3 /* ABORTED */ });
}
}

View File

@ -37,6 +37,12 @@ interface SearchResult {
state?: string;
}
enum IssueSource {
VSCode = 'vscode',
Extension = 'extension',
Marketplace = 'marketplace'
}
export interface IssueReporterConfiguration extends IWindowConfiguration {
windowId: number;
disableExtensions: boolean;
@ -53,6 +59,7 @@ export interface IssueReporterConfiguration extends IWindowConfiguration {
commit: string | undefined;
date: string | undefined;
reportIssueUrl: string | undefined;
reportMarketplaceIssueUrl: string | undefined;
}
}
@ -326,17 +333,18 @@ export class IssueReporter extends Disposable {
hide(problemSourceHelpText);
}
const fileOnExtension = JSON.parse(value);
this.issueReporterModel.update({ fileOnExtension: fileOnExtension });
let fileOnExtension, fileOnMarketplace = false;
if (value === IssueSource.Extension) {
fileOnExtension = true;
} else if (value === IssueSource.Marketplace) {
fileOnMarketplace = true;
}
this.issueReporterModel.update({ fileOnExtension, fileOnMarketplace });
this.render();
const title = (<HTMLInputElement>this.getElementById('issue-title')).value;
if (fileOnExtension) {
this.searchExtensionIssues(title);
} else {
const description = this.issueReporterModel.getData().issueDescription;
this.searchVSCodeIssues(title, description);
}
this.searchIssues(title, fileOnExtension, fileOnMarketplace);
});
this.addEventListener('description', 'input', (e: Event) => {
@ -353,23 +361,19 @@ export class IssueReporter extends Disposable {
this.addEventListener('issue-title', 'input', (e: Event) => {
const title = (<HTMLInputElement>e.target).value;
const lengthValidationMessage = this.getElementById('issue-title-length-validation-error');
if (title && this.getIssueUrlWithTitle(title).length > MAX_URL_LENGTH) {
const issueUrl = this.getIssueUrl();
if (title && this.getIssueUrlWithTitle(title, issueUrl).length > MAX_URL_LENGTH) {
show(lengthValidationMessage);
} else {
hide(lengthValidationMessage);
}
const fileOnExtension = this.issueReporterModel.fileOnExtension();
if (fileOnExtension === undefined) {
const issueSource = this.getElementById<HTMLSelectElement>('issue-source');
if (!issueSource || issueSource.value === '') {
return;
}
if (fileOnExtension) {
this.searchExtensionIssues(title);
} else {
const description = this.issueReporterModel.getData().issueDescription;
this.searchVSCodeIssues(title, description);
}
const { fileOnExtension, fileOnMarketplace } = this.issueReporterModel.getData();
this.searchIssues(title, fileOnExtension, fileOnMarketplace);
});
this.previewButton.onDidClick(() => this.createIssue());
@ -489,6 +493,19 @@ export class IssueReporter extends Disposable {
}
}
private searchIssues(title: string, fileOnExtension: boolean | undefined, fileOnMarketplace: boolean | undefined): void {
if (fileOnExtension) {
return this.searchExtensionIssues(title);
}
if (fileOnMarketplace) {
return this.searchMarketplaceIssues(title);
}
const description = this.issueReporterModel.getData().issueDescription;
this.searchVSCodeIssues(title, description);
}
private searchExtensionIssues(title: string): void {
const url = this.getExtensionGitHubUrl();
if (title) {
@ -509,6 +526,15 @@ export class IssueReporter extends Disposable {
this.clearSearchResults();
}
private searchMarketplaceIssues(title: string): void {
if (title) {
const gitHubInfo = this.parseGitHubUrl(this.configuration.product.reportMarketplaceIssueUrl!);
if (gitHubInfo) {
return this.searchGitHub(`${gitHubInfo.owner}/${gitHubInfo.repositoryName}`, title);
}
}
}
private clearSearchResults(): void {
const similarIssues = this.getElementById('similar-issues')!;
similarIssues.innerText = '';
@ -636,7 +662,7 @@ export class IssueReporter extends Disposable {
reset(typeSelect,
makeOption(IssueType.Bug, localize('bugReporter', "Bug Report")),
makeOption(IssueType.FeatureRequest, localize('featureRequest', "Feature Request")),
makeOption(IssueType.PerformanceIssue, localize('performanceIssue', "Performance Issue"))
makeOption(IssueType.PerformanceIssue, localize('performanceIssue', "Performance Issue")),
);
typeSelect.value = issueType.toString();
@ -666,19 +692,15 @@ export class IssueReporter extends Disposable {
}
sourceSelect.innerText = '';
if (issueType === IssueType.FeatureRequest) {
sourceSelect.append(...[
this.makeOption('', localize('selectSource', "Select source"), true),
this.makeOption('false', localize('vscode', "Visual Studio Code"), false),
this.makeOption('true', localize('extension', "An extension"), false)
]);
} else {
sourceSelect.append(...[
this.makeOption('', localize('selectSource', "Select source"), true),
this.makeOption('false', localize('vscode', "Visual Studio Code"), false),
this.makeOption('true', localize('extension', "An extension"), false),
this.makeOption('', localize('unknown', "Don't Know"), false)
]);
sourceSelect.append(this.makeOption('', localize('selectSource', "Select source"), true));
sourceSelect.append(this.makeOption('vscode', localize('vscode', "Visual Studio Code"), false));
sourceSelect.append(this.makeOption('extension', localize('extension', "An extension"), false));
if (this.configuration.product.reportMarketplaceIssueUrl) {
sourceSelect.append(this.makeOption('marketplace', localize('marketplace', "Extensions marketplace"), false));
}
if (issueType !== IssueType.FeatureRequest) {
sourceSelect.append(this.makeOption('', localize('unknown', "Don't know"), false));
}
if (selected !== -1 && selected < sourceSelect.options.length) {
@ -691,7 +713,7 @@ export class IssueReporter extends Disposable {
private renderBlocks(): void {
// Depending on Issue Type, we render different blocks and text
const { issueType, fileOnExtension } = this.issueReporterModel.getData();
const { issueType, fileOnExtension, fileOnMarketplace } = this.issueReporterModel.getData();
const blockContainer = this.getElementById('block-container');
const systemBlock = document.querySelector('.block-system');
const processBlock = document.querySelector('.block-process');
@ -715,29 +737,35 @@ export class IssueReporter extends Disposable {
hide(extensionSelector);
if (issueType === IssueType.Bug) {
show(blockContainer);
show(systemBlock);
show(problemSource);
show(experimentsBlock);
if (!fileOnMarketplace) {
show(blockContainer);
show(systemBlock);
show(experimentsBlock);
}
if (fileOnExtension) {
show(extensionSelector);
} else {
} else if (!fileOnMarketplace) {
show(extensionsBlock);
}
reset(descriptionTitle, localize('stepsToReproduce', "Steps to Reproduce"), $('span.required-input', undefined, '*'));
reset(descriptionSubtitle, localize('bugDescription', "Share the steps needed to reliably reproduce the problem. Please include actual and expected results. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub."));
} else if (issueType === IssueType.PerformanceIssue) {
show(blockContainer);
show(systemBlock);
show(processBlock);
show(workspaceBlock);
show(problemSource);
show(experimentsBlock);
if (!fileOnMarketplace) {
show(blockContainer);
show(systemBlock);
show(processBlock);
show(workspaceBlock);
show(experimentsBlock);
}
if (fileOnExtension) {
show(extensionSelector);
} else {
} else if (!fileOnMarketplace) {
show(extensionsBlock);
}
@ -845,13 +873,13 @@ export class IssueReporter extends Disposable {
const issueTitle = (<HTMLInputElement>this.getElementById('issue-title')).value;
const issueBody = this.issueReporterModel.serialize();
const issueUrl = this.issueReporterModel.fileOnExtension() ? this.getExtensionGitHubUrl() : this.configuration.product.reportIssueUrl!;
const issueUrl = this.getIssueUrl();
const gitHubDetails = this.parseGitHubUrl(issueUrl);
if (this.configuration.data.githubAccessToken && gitHubDetails) {
return this.submitToGitHub(issueTitle, issueBody, gitHubDetails);
}
const baseUrl = this.getIssueUrlWithTitle((<HTMLInputElement>this.getElementById('issue-title')).value);
const baseUrl = this.getIssueUrlWithTitle((<HTMLInputElement>this.getElementById('issue-title')).value, issueUrl);
let url = baseUrl + `&body=${encodeURIComponent(issueBody)}`;
if (url.length > MAX_URL_LENGTH) {
@ -881,6 +909,14 @@ export class IssueReporter extends Disposable {
});
}
private getIssueUrl(): string {
return this.issueReporterModel.fileOnExtension()
? this.getExtensionGitHubUrl()
: this.issueReporterModel.getData().fileOnMarketplace
? this.configuration.product.reportMarketplaceIssueUrl!
: this.configuration.product.reportIssueUrl!;
}
private parseGitHubUrl(url: string): undefined | { repositoryName: string, owner: string } {
// Assumes a GitHub url to a particular repo, https://github.com/repositoryName/owner.
// Repository name and owner cannot contain '/'
@ -909,16 +945,12 @@ export class IssueReporter extends Disposable {
return repositoryUrl;
}
private getIssueUrlWithTitle(issueTitle: string): string {
let repositoryUrl = this.configuration.product.reportIssueUrl;
private getIssueUrlWithTitle(issueTitle: string, repositoryUrl: string): string {
if (this.issueReporterModel.fileOnExtension()) {
const extensionGitHubUrl = this.getExtensionGitHubUrl();
if (extensionGitHubUrl) {
repositoryUrl = extensionGitHubUrl + '/issues/new';
}
repositoryUrl = repositoryUrl + '/issues/new';
}
const queryStringPrefix = this.configuration.product.reportIssueUrl && this.configuration.product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&';
const queryStringPrefix = repositoryUrl.indexOf('?') === -1 ? '?' : '&';
return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
}
@ -1156,7 +1188,7 @@ export class IssueReporter extends Disposable {
),
...extensions.map(extension => $('tr', undefined,
$('td', undefined, extension.name),
$('td', undefined, extension.publisher.substr(0, 3)),
$('td', undefined, extension.publisher?.substr(0, 3) ?? 'N/A'),
$('td', undefined, extension.version),
))
);

View File

@ -26,6 +26,7 @@ export interface IssueReporterData {
enabledNonThemeExtesions?: IssueReporterExtensionData[];
extensionsDisabled?: boolean;
fileOnExtension?: boolean;
fileOnMarketplace?: boolean;
selectedExtension?: IssueReporterExtensionData;
actualSearchResults?: ISettingSearchResult[];
query?: string;
@ -110,30 +111,30 @@ ${this.getInfos()}
let info = '';
if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) {
if (this._data.includeSystemInfo && this._data.systemInfo) {
if (!this._data.fileOnMarketplace && this._data.includeSystemInfo && this._data.systemInfo) {
info += this.generateSystemInfoMd();
}
}
if (this._data.issueType === IssueType.PerformanceIssue) {
if (this._data.includeProcessInfo) {
if (!this._data.fileOnMarketplace && this._data.includeProcessInfo) {
info += this.generateProcessInfoMd();
}
if (this._data.includeWorkspaceInfo) {
if (!this._data.fileOnMarketplace && this._data.includeWorkspaceInfo) {
info += this.generateWorkspaceInfoMd();
}
}
if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) {
if (!this._data.fileOnExtension && this._data.includeExtensions) {
if (!this._data.fileOnMarketplace && !this._data.fileOnExtension && this._data.includeExtensions) {
info += this.generateExtensionsMd();
}
}
if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) {
if (this._data.includeExperiments && this._data.experimentInfo) {
if (!this._data.fileOnMarketplace && this._data.includeExperiments && this._data.experimentInfo) {
info += this.generateExperimentsInfoMd();
}
}
@ -238,7 +239,7 @@ ${this._data.experimentInfo}
const tableHeader = `Extension|Author (truncated)|Version
---|---|---`;
const table = this._data.enabledNonThemeExtesions.map(e => {
return `${e.name}|${e.publisher.substr(0, 3)}|${e.version}`;
return `${e.name}|${e.publisher?.substr(0, 3) ?? 'N/A'}|${e.version}`;
}).join('\n');
return `<details><summary>Extensions (${this._data.enabledNonThemeExtesions.length})</summary>

View File

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { homedir } from 'os';
import { constants, existsSync, statSync, unlinkSync, chmodSync, truncateSync, readFileSync } from 'fs';
import { existsSync, statSync, unlinkSync, chmodSync, truncateSync, readFileSync } from 'fs';
import { spawn, ChildProcess, SpawnOptions } from 'child_process';
import { buildHelpMessage, buildVersionMessage, OPTIONS } from 'vs/platform/environment/node/argv';
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
@ -23,7 +23,6 @@ function shouldSpawnCliProcess(argv: NativeParsedArgs): boolean {
return !!argv['install-source']
|| !!argv['list-extensions']
|| !!argv['install-extension']
|| !!argv['install-builtin-extension']
|| !!argv['uninstall-extension']
|| !!argv['locate-extension']
|| !!argv['telemetry'];
@ -84,8 +83,8 @@ export async function main(argv: string[]): Promise<any> {
let restoreMode = false;
if (!!args['file-chmod']) {
targetMode = statSync(target).mode;
if (!(targetMode & constants.S_IWUSR)) {
chmodSync(target, targetMode | constants.S_IWUSR);
if (!(targetMode & 0o200 /* File mode indicating writable by owner */)) {
chmodSync(target, targetMode | 0o200);
restoreMode = true;
}
}

View File

@ -13,7 +13,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IExtensionManagementService, IExtensionGalleryService, IExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagement';
@ -46,6 +46,7 @@ import { ILocalizationsService } from 'vs/platform/localizations/common/localiza
import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { VSBuffer } from 'vs/base/common/buffer';
import { cwd } from 'vs/base/common/process';
class CliMain extends Disposable {
@ -94,9 +95,12 @@ class CliMain extends Disposable {
private async initServices(): Promise<[IInstantiationService, AppInsightsAppender[]]> {
const services = new ServiceCollection();
// Product
const productService = { _serviceBrand: undefined, ...product };
services.set(IProductService, productService);
// Environment
const environmentService = new NativeEnvironmentService(this.argv);
services.set(IEnvironmentService, environmentService);
const environmentService = new NativeEnvironmentService(this.argv, productService);
services.set(INativeEnvironmentService, environmentService);
// Init folders
@ -131,9 +135,6 @@ class CliMain extends Disposable {
const stateService = new StateService(environmentService, logService);
services.set(IStateService, stateService);
// Product
services.set(IProductService, { _serviceBrand: undefined, ...product });
const { appRoot, extensionsPath, extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService;
// Request
@ -149,15 +150,15 @@ class CliMain extends Disposable {
// Telemetry
const appenders: AppInsightsAppender[] = [];
if (isBuilt && !extensionDevelopmentLocationURI && !environmentService.disableTelemetry && product.enableTelemetry) {
if (product.aiConfig && product.aiConfig.asimovKey) {
appenders.push(new AppInsightsAppender('monacoworkbench', null, product.aiConfig.asimovKey));
if (isBuilt && !extensionDevelopmentLocationURI && !environmentService.disableTelemetry && productService.enableTelemetry) {
if (productService.aiConfig && productService.aiConfig.asimovKey) {
appenders.push(new AppInsightsAppender('monacoworkbench', null, productService.aiConfig.asimovKey));
}
const config: ITelemetryServiceConfig = {
appender: combinedAppender(...appenders),
sendErrorTelemetry: false,
commonProperties: resolveCommonProperties(fileService, release(), process.arch, product.commit, product.version, stateService.getItem('telemetry.machineId'), product.msftInternalDomains, installSourcePath),
commonProperties: resolveCommonProperties(fileService, release(), process.arch, productService.commit, productService.version, stateService.getItem('telemetry.machineId'), productService.msftInternalDomains, installSourcePath),
piiPaths: [appRoot, extensionsPath]
};
@ -217,7 +218,7 @@ class CliMain extends Disposable {
}
private asExtensionIdOrVSIX(inputs: string[]): (string | URI)[] {
return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(process.cwd(), input)) : input);
return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(cwd(), input)) : input);
}
private async setInstallSource(environmentService: INativeEnvironmentService, fileService: IFileService, installSource: string): Promise<void> {