mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-29 01:25:37 -05:00
Merge from vscode 2c306f762bf9c3db82dc06c7afaa56ef46d72f79 (#14050)
* Merge from vscode 2c306f762bf9c3db82dc06c7afaa56ef46d72f79 * Fix breaks * Extension management fixes * Fix breaks in windows bundling * Fix/skip failing tests * Update distro * Add clear to nuget.config * Add hygiene task * Bump distro * Fix hygiene issue * Add build to hygiene exclusion * Update distro * Update hygiene * Hygiene exclusions * Update tsconfig * Bump distro for server breaks * Update build config * Update darwin path * Add done calls to notebook tests * Skip failing tests * Disable smoke tests
This commit is contained in:
@@ -23,6 +23,7 @@ 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'];
|
||||
@@ -95,9 +96,9 @@ export async function main(argv: string[]): Promise<any> {
|
||||
// On Windows we use a different strategy of saving the file
|
||||
// by first truncating the file and then writing with r+ mode.
|
||||
// This helps to save hidden files on Windows
|
||||
// (see https://github.com/Microsoft/vscode/issues/931) and
|
||||
// (see https://github.com/microsoft/vscode/issues/931) and
|
||||
// prevent removing alternate data streams
|
||||
// (see https://github.com/Microsoft/vscode/issues/6363)
|
||||
// (see https://github.com/microsoft/vscode/issues/6363)
|
||||
fs.truncateSync(target, 0);
|
||||
writeFileSync(target, data, { flag: 'r+' });
|
||||
} else {
|
||||
@@ -122,10 +123,6 @@ export async function main(argv: string[]): Promise<any> {
|
||||
'ELECTRON_NO_ATTACH_CONSOLE': '1'
|
||||
};
|
||||
|
||||
if (args['force-user-env']) {
|
||||
env['VSCODE_FORCE_USER_ENV'] = '1';
|
||||
}
|
||||
|
||||
delete env['ELECTRON_RUN_AS_NODE'];
|
||||
|
||||
const processCallbacks: ((child: ChildProcess) => Promise<void>)[] = [];
|
||||
@@ -138,7 +135,7 @@ export async function main(argv: string[]): Promise<any> {
|
||||
child.stdout!.on('data', (data: Buffer) => console.log(data.toString('utf8').trim()));
|
||||
child.stderr!.on('data', (data: Buffer) => console.log(data.toString('utf8').trim()));
|
||||
|
||||
await new Promise<void>(c => child.once('exit', () => c()));
|
||||
await new Promise<void>(resolve => child.once('exit', () => resolve()));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -154,43 +151,41 @@ export async function main(argv: string[]): Promise<any> {
|
||||
|
||||
// Read from stdin: we require a single "-" argument to be passed in order to start reading from
|
||||
// stdin. We do this because there is no reliable way to find out if data is piped to stdin. Just
|
||||
// checking for stdin being connected to a TTY is not enough (https://github.com/Microsoft/vscode/issues/40351)
|
||||
// checking for stdin being connected to a TTY is not enough (https://github.com/microsoft/vscode/issues/40351)
|
||||
|
||||
if (args._.length === 0) {
|
||||
if (hasReadStdinArg) {
|
||||
stdinFilePath = getStdinFilePath();
|
||||
if (hasReadStdinArg) {
|
||||
stdinFilePath = getStdinFilePath();
|
||||
|
||||
// returns a file path where stdin input is written into (write in progress).
|
||||
try {
|
||||
readFromStdin(stdinFilePath, !!verbose); // throws error if file can not be written
|
||||
// returns a file path where stdin input is written into (write in progress).
|
||||
try {
|
||||
readFromStdin(stdinFilePath, !!verbose); // throws error if file can not be written
|
||||
|
||||
// Make sure to open tmp file
|
||||
addArg(argv, stdinFilePath);
|
||||
// Make sure to open tmp file
|
||||
addArg(argv, stdinFilePath);
|
||||
|
||||
// Enable --wait to get all data and ignore adding this to history
|
||||
addArg(argv, '--wait');
|
||||
addArg(argv, '--skip-add-to-recently-opened');
|
||||
args.wait = true;
|
||||
// Enable --wait to get all data and ignore adding this to history
|
||||
addArg(argv, '--wait');
|
||||
addArg(argv, '--skip-add-to-recently-opened');
|
||||
args.wait = true;
|
||||
|
||||
console.log(`Reading from stdin via: ${stdinFilePath}`);
|
||||
} catch (e) {
|
||||
console.log(`Failed to create file to read via stdin: ${e.toString()}`);
|
||||
stdinFilePath = undefined;
|
||||
}
|
||||
} else {
|
||||
|
||||
// If the user pipes data via stdin but forgot to add the "-" argument, help by printing a message
|
||||
// if we detect that data flows into via stdin after a certain timeout.
|
||||
processCallbacks.push(_ => stdinDataListener(1000).then(dataReceived => {
|
||||
if (dataReceived) {
|
||||
if (isWindows) {
|
||||
console.log(`Run with '${product.applicationName} -' to read output from another program (e.g. 'echo Hello World | ${product.applicationName} -').`);
|
||||
} else {
|
||||
console.log(`Run with '${product.applicationName} -' to read from stdin (e.g. 'ps aux | grep code | ${product.applicationName} -').`);
|
||||
}
|
||||
}
|
||||
}));
|
||||
console.log(`Reading from stdin via: ${stdinFilePath}`);
|
||||
} catch (e) {
|
||||
console.log(`Failed to create file to read via stdin: ${e.toString()}`);
|
||||
stdinFilePath = undefined;
|
||||
}
|
||||
} else {
|
||||
|
||||
// If the user pipes data via stdin but forgot to add the "-" argument, help by printing a message
|
||||
// if we detect that data flows into via stdin after a certain timeout.
|
||||
processCallbacks.push(_ => stdinDataListener(1000).then(dataReceived => {
|
||||
if (dataReceived) {
|
||||
if (isWindows) {
|
||||
console.log(`Run with '${product.applicationName} -' to read output from another program (e.g. 'echo Hello World | ${product.applicationName} -').`);
|
||||
} else {
|
||||
console.log(`Run with '${product.applicationName} -' to read from stdin (e.g. 'ps aux | grep code | ${product.applicationName} -').`);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,13 +327,13 @@ export async function main(argv: string[]): Promise<any> {
|
||||
const child = spawn(process.execPath, argv.slice(2), options);
|
||||
|
||||
if (args.wait && waitMarkerFilePath) {
|
||||
return new Promise<void>(c => {
|
||||
return new Promise<void>(resolve => {
|
||||
|
||||
// Complete when process exits
|
||||
child.once('exit', () => c(undefined));
|
||||
child.once('exit', () => resolve(undefined));
|
||||
|
||||
// Complete when wait marker file is deleted
|
||||
whenDeleted(waitMarkerFilePath!).then(c, c);
|
||||
whenDeleted(waitMarkerFilePath!).then(resolve, resolve);
|
||||
}).then(() => {
|
||||
|
||||
// Make sure to delete the tmp stdin file if we have any
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { raceTimeout } from 'vs/base/common/async';
|
||||
import * as semver from 'vs/base/common/semver/semver';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
@@ -13,8 +14,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
|
||||
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension, InstallOptions } 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';
|
||||
@@ -30,7 +31,7 @@ import { mkdirp, writeFile } from 'vs/base/node/pfs';
|
||||
import { getBaseLabel } from 'vs/base/common/labels';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { StateService } from 'vs/platform/state/node/stateService';
|
||||
import { ILogService, getLogLevel } from 'vs/platform/log/common/log';
|
||||
import { ILogService, getLogLevel, LogLevel, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { areSameExtensions, adoptToGalleryExtensionId, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -69,14 +70,15 @@ export function getIdAndVersion(id: string): [string, string | undefined] {
|
||||
return [adoptToGalleryExtensionId(id), undefined];
|
||||
}
|
||||
|
||||
type InstallExtensionInfo = { id: string, version?: string, installOptions: InstallOptions };
|
||||
|
||||
export class Main {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService
|
||||
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
||||
) { }
|
||||
|
||||
async run(argv: NativeParsedArgs): Promise<void> {
|
||||
@@ -84,14 +86,14 @@ export class Main {
|
||||
await this.setInstallSource(argv['install-source']);
|
||||
} else if (argv['list-extensions']) {
|
||||
await this.listExtensions(!!argv['show-versions'], argv['category']);
|
||||
} else if (argv['install-extension']) {
|
||||
await this.installExtensions(argv['install-extension'], !!argv['force'], !!argv['do-not-sync']);
|
||||
} else if (argv['install-extension'] || argv['install-builtin-extension']) {
|
||||
await this.installExtensions(argv['install-extension'] || [], argv['install-builtin-extension'] || [], !!argv['do-not-sync'], !!argv['force']);
|
||||
} else if (argv['uninstall-extension']) {
|
||||
await this.uninstallExtension(argv['uninstall-extension']);
|
||||
await this.uninstallExtension(argv['uninstall-extension'], !!argv['force']);
|
||||
} else if (argv['locate-extension']) {
|
||||
await this.locateExtension(argv['locate-extension']);
|
||||
} else if (argv['telemetry']) {
|
||||
console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath ? this.environmentService.extensionsPath : undefined));
|
||||
console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,88 +126,164 @@ export class Main {
|
||||
extensions.forEach(e => console.log(getId(e.manifest, showVersions)));
|
||||
}
|
||||
|
||||
private async installExtensions(extensions: string[], force: boolean, doNotSync: boolean): Promise<void> {
|
||||
async installExtensions(extensions: string[], builtinExtensionIds: string[], isMachineScoped: boolean, force: boolean): Promise<void> {
|
||||
const failed: string[] = [];
|
||||
const installedExtensionsManifests: IExtensionManifest[] = [];
|
||||
if (extensions.length) {
|
||||
console.log(localize('installingExtensions', "Installing extensions..."));
|
||||
}
|
||||
|
||||
for (const extension of extensions) {
|
||||
try {
|
||||
const manifest = await this.installExtension(extension, force, doNotSync);
|
||||
if (manifest) {
|
||||
installedExtensionsManifests.push(manifest);
|
||||
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const checkIfNotInstalled = (id: string, version?: string): boolean => {
|
||||
const installedExtension = installed.find(i => areSameExtensions(i.identifier, { id }));
|
||||
if (installedExtension) {
|
||||
if (!version && !force) {
|
||||
console.log(localize('alreadyInstalled-checkAndUpdate', "Extension '{0}' v{1} is already installed. Use '--force' option to update to latest version or provide '@<version>' to install a specific version, for example: '{2}@1.2.3'.", id, installedExtension.manifest.version, id));
|
||||
return false;
|
||||
}
|
||||
if (version && installedExtension.manifest.version === version) {
|
||||
console.log(localize('alreadyInstalled', "Extension '{0}' is already installed.", `${id}@${version}`));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const vsixs: string[] = [];
|
||||
const installExtensionInfos: InstallExtensionInfo[] = [];
|
||||
for (const extension of extensions) {
|
||||
if (/\.vsix$/i.test(extension)) {
|
||||
vsixs.push(extension);
|
||||
} else {
|
||||
const [id, version] = getIdAndVersion(extension);
|
||||
if (checkIfNotInstalled(id, version)) {
|
||||
installExtensionInfos.push({ id, version, installOptions: { isBuiltin: false, isMachineScoped } });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.message || err.stack || err);
|
||||
failed.push(extension);
|
||||
}
|
||||
}
|
||||
for (const extension of builtinExtensionIds) {
|
||||
const [id, version] = getIdAndVersion(extension);
|
||||
if (checkIfNotInstalled(id, version)) {
|
||||
installExtensionInfos.push({ id, version, installOptions: { isBuiltin: true, isMachineScoped: false } });
|
||||
}
|
||||
}
|
||||
|
||||
if (vsixs.length) {
|
||||
await Promise.all(vsixs.map(async vsix => {
|
||||
try {
|
||||
const manifest = await this.installVSIX(vsix, force);
|
||||
if (manifest) {
|
||||
installedExtensionsManifests.push(manifest);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.message || err.stack || err);
|
||||
failed.push(vsix);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (installExtensionInfos.length) {
|
||||
|
||||
const galleryExtensions = await this.getGalleryExtensions(installExtensionInfos);
|
||||
|
||||
await Promise.all(installExtensionInfos.map(async extensionInfo => {
|
||||
const gallery = galleryExtensions.get(extensionInfo.id.toLowerCase());
|
||||
if (gallery) {
|
||||
try {
|
||||
const manifest = await this.installFromGallery(extensionInfo, gallery, installed, force);
|
||||
if (manifest) {
|
||||
installedExtensionsManifests.push(manifest);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.message || err.stack || err);
|
||||
failed.push(extensionInfo.id);
|
||||
}
|
||||
} else {
|
||||
console.error(`${notFound(extensionInfo.version ? `${extensionInfo.id}@${extensionInfo.version}` : extensionInfo.id)}\n${useId}`);
|
||||
failed.push(extensionInfo.id);
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
if (installedExtensionsManifests.some(manifest => isLanguagePackExtension(manifest))) {
|
||||
await this.updateLocalizationsCache();
|
||||
}
|
||||
return failed.length ? Promise.reject(localize('installation failed', "Failed Installing Extensions: {0}", failed.join(', '))) : Promise.resolve();
|
||||
|
||||
if (failed.length) {
|
||||
throw new Error(localize('installation failed', "Failed Installing Extensions: {0}", failed.join(', ')));
|
||||
}
|
||||
}
|
||||
|
||||
private async installExtension(extension: string, force: boolean, doNotSync: boolean): Promise<IExtensionManifest | null> {
|
||||
if (/\.vsix$/i.test(extension)) {
|
||||
extension = path.isAbsolute(extension) ? extension : path.join(process.cwd(), extension);
|
||||
|
||||
const manifest = await getManifest(extension);
|
||||
const valid = await this.validate(manifest, force);
|
||||
|
||||
if (valid) {
|
||||
return this.extensionManagementService.install(URI.file(extension), doNotSync).then(id => {
|
||||
console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed.", getBaseLabel(extension)));
|
||||
return manifest;
|
||||
}, error => {
|
||||
if (isPromiseCanceledError(error)) {
|
||||
console.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", getBaseLabel(extension)));
|
||||
return null;
|
||||
} else {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
});
|
||||
private async installVSIX(vsix: string, force: boolean): Promise<IExtensionManifest | null> {
|
||||
vsix = path.isAbsolute(vsix) ? vsix : path.join(process.cwd(), vsix);
|
||||
const manifest = await getManifest(vsix);
|
||||
const valid = await this.validate(manifest, force);
|
||||
if (valid) {
|
||||
try {
|
||||
await this.extensionManagementService.install(URI.file(vsix));
|
||||
console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed.", getBaseLabel(vsix)));
|
||||
return manifest;
|
||||
} catch (error) {
|
||||
if (isPromiseCanceledError(error)) {
|
||||
console.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", getBaseLabel(vsix)));
|
||||
return null;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async getGalleryExtensions(extensions: InstallExtensionInfo[]): Promise<Map<string, IGalleryExtension>> {
|
||||
const extensionIds = extensions.filter(({ version }) => version === undefined).map(({ id }) => id);
|
||||
const extensionsWithIdAndVersion = extensions.filter(({ version }) => version !== undefined);
|
||||
|
||||
const galleryExtensions = new Map<string, IGalleryExtension>();
|
||||
await Promise.all([
|
||||
(async () => {
|
||||
const result = await this.extensionGalleryService.getExtensions(extensionIds, CancellationToken.None);
|
||||
result.forEach(extension => galleryExtensions.set(extension.identifier.id.toLowerCase(), extension));
|
||||
})(),
|
||||
Promise.all(extensionsWithIdAndVersion.map(async ({ id, version }) => {
|
||||
const extension = await this.extensionGalleryService.getCompatibleExtension({ id }, version);
|
||||
if (extension) {
|
||||
galleryExtensions.set(extension.identifier.id.toLowerCase(), extension);
|
||||
}
|
||||
}))
|
||||
]);
|
||||
|
||||
return galleryExtensions;
|
||||
}
|
||||
|
||||
private async installFromGallery({ id, version, installOptions }: InstallExtensionInfo, galleryExtension: IGalleryExtension, installed: ILocalExtension[], force: boolean): Promise<IExtensionManifest | null> {
|
||||
const manifest = await this.extensionGalleryService.getManifest(galleryExtension, CancellationToken.None);
|
||||
const installedExtension = installed.find(e => areSameExtensions(e.identifier, galleryExtension.identifier));
|
||||
if (installedExtension) {
|
||||
if (galleryExtension.version === installedExtension.manifest.version) {
|
||||
console.log(localize('alreadyInstalled', "Extension '{0}' is already installed.", version ? `${id}@${version}` : id));
|
||||
return null;
|
||||
}
|
||||
console.log(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, galleryExtension.version));
|
||||
}
|
||||
|
||||
const [id, version] = getIdAndVersion(extension);
|
||||
return this.extensionManagementService.getInstalled(ExtensionType.User)
|
||||
.then(installed => this.extensionGalleryService.getCompatibleExtension({ id }, version)
|
||||
.then<IGalleryExtension>(null, err => {
|
||||
if (err.responseText) {
|
||||
try {
|
||||
const response = JSON.parse(err.responseText);
|
||||
return Promise.reject(response.message);
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
return Promise.reject(err);
|
||||
})
|
||||
.then(async extension => {
|
||||
if (!extension) {
|
||||
return Promise.reject(new Error(`${notFound(version ? `${id}@${version}` : id)}\n${useId}`));
|
||||
}
|
||||
|
||||
const manifest = await this.extensionGalleryService.getManifest(extension, CancellationToken.None);
|
||||
const [installedExtension] = installed.filter(e => areSameExtensions(e.identifier, { id }));
|
||||
if (installedExtension) {
|
||||
if (extension.version === installedExtension.manifest.version) {
|
||||
console.log(localize('alreadyInstalled', "Extension '{0}' is already installed.", version ? `${id}@${version}` : id));
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (!version && !force) {
|
||||
console.log(localize('forceUpdate', "Extension '{0}' v{1} is already installed, but a newer version {2} is available in the marketplace. Use '--force' option to update to newer version.", id, installedExtension.manifest.version, extension.version));
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
console.log(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, extension.version));
|
||||
}
|
||||
await this.installFromGallery(id, extension, doNotSync);
|
||||
return manifest;
|
||||
}));
|
||||
try {
|
||||
if (installOptions.isBuiltin) {
|
||||
console.log(localize('installing builtin ', "Installing builtin extension '{0}' v{1}...", id, galleryExtension.version));
|
||||
} else {
|
||||
console.log(localize('installing', "Installing extension '{0}' v{1}...", id, galleryExtension.version));
|
||||
}
|
||||
await this.extensionManagementService.installFromGallery(galleryExtension, installOptions);
|
||||
console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, galleryExtension.version));
|
||||
return manifest;
|
||||
} catch (error) {
|
||||
if (isPromiseCanceledError(error)) {
|
||||
console.log(localize('cancelInstall', "Cancelled installing extension '{0}'.", id));
|
||||
return null;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async validate(manifest: IExtensionManifest, force: boolean): Promise<boolean> {
|
||||
@@ -213,8 +291,6 @@ export class Main {
|
||||
throw new Error('Invalid vsix');
|
||||
}
|
||||
|
||||
const semver = await import('semver-umd');
|
||||
|
||||
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
|
||||
const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && semver.gt(local.manifest.version, manifest.version));
|
||||
@@ -227,22 +303,7 @@ export class Main {
|
||||
return true;
|
||||
}
|
||||
|
||||
private async installFromGallery(id: string, extension: IGalleryExtension, doNotSync: boolean): Promise<void> {
|
||||
console.log(localize('installing', "Installing extension '{0}' v{1}...", id, extension.version));
|
||||
|
||||
try {
|
||||
await this.extensionManagementService.installFromGallery(extension, doNotSync);
|
||||
console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, extension.version));
|
||||
} catch (error) {
|
||||
if (isPromiseCanceledError(error)) {
|
||||
console.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", id));
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async uninstallExtension(extensions: string[]): Promise<void> {
|
||||
private async uninstallExtension(extensions: string[], force: boolean): Promise<void> {
|
||||
async function getExtensionId(extensionDescription: string): Promise<string> {
|
||||
if (!/\.vsix$/i.test(extensionDescription)) {
|
||||
return extensionDescription;
|
||||
@@ -256,13 +317,21 @@ export class Main {
|
||||
const uninstalledExtensions: ILocalExtension[] = [];
|
||||
for (const extension of extensions) {
|
||||
const id = await getExtensionId(extension);
|
||||
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id }));
|
||||
const installed = await this.extensionManagementService.getInstalled();
|
||||
const extensionToUninstall = installed.find(e => areSameExtensions(e.identifier, { id }));
|
||||
if (!extensionToUninstall) {
|
||||
return Promise.reject(new Error(`${notInstalled(id)}\n${useId}`));
|
||||
throw new Error(`${notInstalled(id)}\n${useId}`);
|
||||
}
|
||||
if (extensionToUninstall.type === ExtensionType.System) {
|
||||
console.log(localize('builtin', "Extension '{0}' is a Built-in extension and cannot be installed", id));
|
||||
return;
|
||||
}
|
||||
if (extensionToUninstall.isBuiltin && !force) {
|
||||
console.log(localize('forceUninstall', "Extension '{0}' is marked as a Built-in extension by user. Please use '--force' option to uninstall it.", id));
|
||||
return;
|
||||
}
|
||||
console.log(localize('uninstalling', "Uninstalling {0}...", id));
|
||||
await this.extensionManagementService.uninstall(extensionToUninstall, true);
|
||||
await this.extensionManagementService.uninstall(extensionToUninstall);
|
||||
uninstalledExtensions.push(extensionToUninstall);
|
||||
console.log(localize('successUninstall', "Extension '{0}' was successfully uninstalled!", id));
|
||||
}
|
||||
@@ -299,8 +368,14 @@ export async function main(argv: NativeParsedArgs): Promise<void> {
|
||||
const services = new ServiceCollection();
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const environmentService = new EnvironmentService(argv);
|
||||
const logService: ILogService = new SpdLogService('cli', environmentService.logsPath, getLogLevel(environmentService));
|
||||
const environmentService = new NativeEnvironmentService(argv);
|
||||
const logLevel = getLogLevel(environmentService);
|
||||
const loggers: ILogService[] = [];
|
||||
loggers.push(new SpdLogService('cli', environmentService.logsPath, logLevel));
|
||||
if (logLevel === LogLevel.Trace) {
|
||||
loggers.push(new ConsoleLogService(logLevel));
|
||||
}
|
||||
const logService = new MultiplexLogService(loggers);
|
||||
process.once('exit', () => logService.dispose());
|
||||
logService.info('main', argv);
|
||||
|
||||
@@ -321,6 +396,8 @@ export async function main(argv: NativeParsedArgs): Promise<void> {
|
||||
await configurationService.initialize();
|
||||
|
||||
services.set(IEnvironmentService, environmentService);
|
||||
services.set(INativeEnvironmentService, environmentService);
|
||||
|
||||
services.set(ILogService, logService);
|
||||
services.set(IConfigurationService, configurationService);
|
||||
services.set(IStateService, new SyncDescriptor(StateService));
|
||||
@@ -341,14 +418,14 @@ export async function main(argv: NativeParsedArgs): Promise<void> {
|
||||
const appenders: AppInsightsAppender[] = [];
|
||||
if (isBuilt && !extensionDevelopmentLocationURI && !environmentService.disableTelemetry && product.enableTelemetry) {
|
||||
if (product.aiConfig && product.aiConfig.asimovKey) {
|
||||
appenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, logService));
|
||||
appenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey));
|
||||
}
|
||||
|
||||
const config: ITelemetryServiceConfig = {
|
||||
appender: combinedAppender(...appenders),
|
||||
sendErrorTelemetry: false,
|
||||
commonProperties: resolveCommonProperties(product.commit, product.version, stateService.getItem('telemetry.machineId'), product.msftInternalDomains, installSourcePath),
|
||||
piiPaths: extensionsPath ? [appRoot, extensionsPath] : [appRoot]
|
||||
piiPaths: [appRoot, extensionsPath]
|
||||
};
|
||||
|
||||
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
|
||||
|
||||
@@ -7,9 +7,57 @@ import { spawn } from 'child_process';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
|
||||
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
|
||||
function getUnixShellEnvironment(logService: ILogService): Promise<typeof process.env> {
|
||||
/**
|
||||
* We need to get the environment from a user's shell.
|
||||
* This should only be done when Code itself is not launched
|
||||
* from within a shell.
|
||||
*/
|
||||
export async function resolveShellEnv(logService: ILogService, args: NativeParsedArgs, env: NodeJS.ProcessEnv): Promise<typeof process.env> {
|
||||
|
||||
// Skip if --force-disable-user-env
|
||||
if (args['force-disable-user-env']) {
|
||||
logService.trace('resolveShellEnv(): skipped (--force-disable-user-env)');
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Skip on windows
|
||||
else if (isWindows) {
|
||||
logService.trace('resolveShellEnv(): skipped (Windows)');
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Skip if running from CLI already
|
||||
else if (isLaunchedFromCli(env) && !args['force-user-env']) {
|
||||
logService.trace('resolveShellEnv(): skipped (VSCODE_CLI is set)');
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Otherwise resolve (macOS, Linux)
|
||||
else {
|
||||
if (isLaunchedFromCli(env)) {
|
||||
logService.trace('resolveShellEnv(): running (--force-user-env)');
|
||||
} else {
|
||||
logService.trace('resolveShellEnv(): running (macOS/Linux)');
|
||||
}
|
||||
|
||||
if (!unixShellEnvPromise) {
|
||||
unixShellEnvPromise = doResolveUnixShellEnv(logService);
|
||||
}
|
||||
|
||||
return unixShellEnvPromise;
|
||||
}
|
||||
}
|
||||
|
||||
let unixShellEnvPromise: Promise<typeof process.env> | undefined = undefined;
|
||||
|
||||
async function doResolveUnixShellEnv(logService: ILogService): Promise<typeof process.env> {
|
||||
const promise = new Promise<typeof process.env>((resolve, reject) => {
|
||||
const runAsNode = process.env['ELECTRON_RUN_AS_NODE'];
|
||||
logService.trace('getUnixShellEnvironment#runAsNode', runAsNode);
|
||||
@@ -66,7 +114,7 @@ function getUnixShellEnvironment(logService: ILogService): Promise<typeof proces
|
||||
delete env['ELECTRON_NO_ATTACH_CONSOLE'];
|
||||
}
|
||||
|
||||
// https://github.com/Microsoft/vscode/issues/22593#issuecomment-336050758
|
||||
// https://github.com/microsoft/vscode/issues/22593#issuecomment-336050758
|
||||
delete env['XDG_RUNTIME_DIR'];
|
||||
|
||||
logService.trace('getUnixShellEnvironment#result', env);
|
||||
@@ -78,33 +126,11 @@ function getUnixShellEnvironment(logService: ILogService): Promise<typeof proces
|
||||
});
|
||||
});
|
||||
|
||||
// swallow errors
|
||||
return promise.catch(() => ({}));
|
||||
}
|
||||
try {
|
||||
return await promise;
|
||||
} catch (error) {
|
||||
logService.error('getUnixShellEnvironment#error', toErrorMessage(error));
|
||||
|
||||
let shellEnvPromise: Promise<typeof process.env> | undefined = undefined;
|
||||
|
||||
/**
|
||||
* We need to get the environment from a user's shell.
|
||||
* This should only be done when Code itself is not launched
|
||||
* from within a shell.
|
||||
*/
|
||||
export function getShellEnvironment(logService: ILogService, environmentService: INativeEnvironmentService): Promise<typeof process.env> {
|
||||
if (!shellEnvPromise) {
|
||||
if (environmentService.args['disable-user-env-probe']) {
|
||||
logService.trace('getShellEnvironment: disable-user-env-probe set, skipping');
|
||||
shellEnvPromise = Promise.resolve({});
|
||||
} else if (isWindows) {
|
||||
logService.trace('getShellEnvironment: running on Windows, skipping');
|
||||
shellEnvPromise = Promise.resolve({});
|
||||
} else if (process.env['VSCODE_CLI'] === '1' && process.env['VSCODE_FORCE_USER_ENV'] !== '1') {
|
||||
logService.trace('getShellEnvironment: running on CLI, skipping');
|
||||
shellEnvPromise = Promise.resolve({});
|
||||
} else {
|
||||
logService.trace('getShellEnvironment: running on Unix');
|
||||
shellEnvPromise = getUnixShellEnvironment(logService);
|
||||
}
|
||||
return {}; // ignore any errors
|
||||
}
|
||||
|
||||
return shellEnvPromise;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user