mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-03 09:35:40 -05:00
Merge from vscode e3c4990c67c40213af168300d1cfeb71d680f877 (#16569)
This commit is contained in:
@@ -9,7 +9,7 @@ import { getGalleryExtensionId, getGalleryExtensionTelemetryData, adoptToGallery
|
||||
import { getOrDefault } from 'vs/base/common/objects';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IPager } from 'vs/base/common/paging';
|
||||
import { IRequestService, asJson, asText } from 'vs/platform/request/common/request';
|
||||
import { IRequestService, asJson, asText, isSuccess } from 'vs/platform/request/common/request';
|
||||
import { IRequestOptions, IRequestContext, IHeaders } from 'vs/base/parts/request/common/request';
|
||||
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
@@ -26,48 +26,48 @@ import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
|
||||
interface IRawGalleryExtensionFile {
|
||||
assetType: string;
|
||||
source: string;
|
||||
readonly assetType: string;
|
||||
readonly source: string;
|
||||
}
|
||||
|
||||
interface IRawGalleryExtensionProperty {
|
||||
key: string;
|
||||
value: string;
|
||||
readonly key: string;
|
||||
readonly value: string;
|
||||
}
|
||||
|
||||
interface IRawGalleryExtensionVersion {
|
||||
version: string;
|
||||
lastUpdated: string;
|
||||
assetUri: string;
|
||||
fallbackAssetUri: string;
|
||||
files: IRawGalleryExtensionFile[];
|
||||
properties?: IRawGalleryExtensionProperty[];
|
||||
readonly version: string;
|
||||
readonly lastUpdated: string;
|
||||
readonly assetUri: string;
|
||||
readonly fallbackAssetUri: string;
|
||||
readonly files: IRawGalleryExtensionFile[];
|
||||
readonly properties?: IRawGalleryExtensionProperty[];
|
||||
}
|
||||
|
||||
interface IRawGalleryExtensionStatistics {
|
||||
statisticName: string;
|
||||
value: number;
|
||||
readonly statisticName: string;
|
||||
readonly value: number;
|
||||
}
|
||||
|
||||
interface IRawGalleryExtension {
|
||||
extensionId: string;
|
||||
extensionName: string;
|
||||
displayName: string;
|
||||
shortDescription: string;
|
||||
publisher: { displayName: string, publisherId: string, publisherName: string; };
|
||||
versions: IRawGalleryExtensionVersion[];
|
||||
statistics: IRawGalleryExtensionStatistics[];
|
||||
flags: string;
|
||||
readonly extensionId: string;
|
||||
readonly extensionName: string;
|
||||
readonly displayName: string;
|
||||
readonly shortDescription: string;
|
||||
readonly publisher: { displayName: string, publisherId: string, publisherName: string; };
|
||||
readonly versions: IRawGalleryExtensionVersion[];
|
||||
readonly statistics: IRawGalleryExtensionStatistics[];
|
||||
readonly flags: string;
|
||||
}
|
||||
|
||||
interface IRawGalleryQueryResult {
|
||||
results: {
|
||||
extensions: IRawGalleryExtension[];
|
||||
resultMetadata: {
|
||||
metadataType: string;
|
||||
metadataItems: {
|
||||
name: string;
|
||||
count: number;
|
||||
readonly results: {
|
||||
readonly extensions: IRawGalleryExtension[];
|
||||
readonly resultMetadata: {
|
||||
readonly metadataType: string;
|
||||
readonly metadataItems: {
|
||||
readonly name: string;
|
||||
readonly count: number;
|
||||
}[];
|
||||
}[]
|
||||
}[];
|
||||
@@ -126,20 +126,20 @@ const PropertyType = {
|
||||
};
|
||||
|
||||
interface ICriterium {
|
||||
filterType: FilterType;
|
||||
value?: string;
|
||||
readonly filterType: FilterType;
|
||||
readonly value?: string;
|
||||
}
|
||||
|
||||
const DefaultPageSize = 10;
|
||||
|
||||
interface IQueryState {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
sortBy: SortBy;
|
||||
sortOrder: SortOrder;
|
||||
flags: Flags;
|
||||
criteria: ICriterium[];
|
||||
assetTypes: string[];
|
||||
readonly pageNumber: number;
|
||||
readonly pageSize: number;
|
||||
readonly sortBy: SortBy;
|
||||
readonly sortOrder: SortOrder;
|
||||
readonly flags: Flags;
|
||||
readonly criteria: ICriterium[];
|
||||
readonly assetTypes: string[];
|
||||
}
|
||||
|
||||
const DefaultQueryState: IQueryState = {
|
||||
@@ -152,10 +152,33 @@ const DefaultQueryState: IQueryState = {
|
||||
assetTypes: []
|
||||
};
|
||||
|
||||
type GalleryServiceQueryClassification = {
|
||||
readonly filterTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly sortBy: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly sortOrder: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly duration: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', 'isMeasurement': true };
|
||||
readonly success: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly requestBodySize: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly responseBodySize?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly statusCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly errorCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
readonly count?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
type QueryTelemetryData = {
|
||||
filterTypes: string[];
|
||||
sortBy: string;
|
||||
sortOrder: string;
|
||||
readonly filterTypes: string[];
|
||||
readonly sortBy: string;
|
||||
readonly sortOrder: string;
|
||||
};
|
||||
|
||||
type GalleryServiceQueryEvent = QueryTelemetryData & {
|
||||
readonly duration: number;
|
||||
readonly success: boolean;
|
||||
readonly requestBodySize: string;
|
||||
readonly responseBodySize?: string;
|
||||
readonly statusCode?: string;
|
||||
readonly errorCode?: string;
|
||||
readonly count?: string;
|
||||
};
|
||||
|
||||
class Query {
|
||||
@@ -239,7 +262,7 @@ function getCoreTranslationAssets(version: IRawGalleryExtensionVersion): [string
|
||||
function getRepositoryAsset(version: IRawGalleryExtensionVersion): IGalleryExtensionAsset | null {
|
||||
if (version.properties) {
|
||||
const results = version.properties.filter(p => p.key === AssetType.Repository);
|
||||
const gitRegExp = new RegExp('((git|ssh|http(s)?)|(git@[\w.]+))(:(//)?)([\w.@\:/\-~]+)(.git)(/)?');
|
||||
const gitRegExp = new RegExp('((git|ssh|http(s)?)|(git@[\\w.]+))(:(//)?)([\\w.@\:/\\-~]+)(.git)(/)?');
|
||||
|
||||
const uri = results.filter(r => gitRegExp.test(r.value))[0];
|
||||
return uri ? { uri: uri.value, fallbackUri: uri.value } : null;
|
||||
@@ -380,13 +403,11 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller
|
||||
/* __GDPR__FRAGMENT__
|
||||
"GalleryExtensionTelemetryData2" : {
|
||||
"index" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"searchText": { "classification": "CustomerContent", "purpose": "FeatureInsight" },
|
||||
"querySource": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
telemetryData: {
|
||||
index: ((query.pageNumber - 1) * query.pageSize) + index,
|
||||
searchText: query.searchText,
|
||||
querySource
|
||||
},
|
||||
preview: getIsPreview(galleryExtension.flags)
|
||||
@@ -489,7 +510,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
const versionAsset = rawExtension.versions.filter(v => v.version === version)[0];
|
||||
if (versionAsset) {
|
||||
const extension = toExtension(rawExtension, versionAsset, 0, query);
|
||||
if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) {
|
||||
if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version, this.productService.date)) {
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
@@ -513,20 +534,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
throw new Error('No extension gallery service configured.');
|
||||
}
|
||||
|
||||
const type = options.names ? 'ids' : (options.text ? 'text' : 'all');
|
||||
let text = options.text || '';
|
||||
const pageSize = getOrDefault(options, o => o.pageSize, 50);
|
||||
|
||||
type GalleryServiceQueryClassification = {
|
||||
type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
text: { classification: 'CustomerContent', purpose: 'FeatureInsight' };
|
||||
};
|
||||
type GalleryServiceQueryEvent = {
|
||||
type: string;
|
||||
text: string;
|
||||
};
|
||||
this.telemetryService.publicLog2<GalleryServiceQueryEvent, GalleryServiceQueryClassification>('galleryService:query', { type, text });
|
||||
|
||||
let query = new Query()
|
||||
.withFlags(Flags.IncludeLatestVersionOnly, Flags.IncludeAssetUri, Flags.IncludeStatistics, Flags.IncludeFiles, Flags.IncludeVersionProperties)
|
||||
.withPage(1, pageSize)
|
||||
@@ -676,6 +686,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
extension.extensionId && extension.extensionId.toLocaleLowerCase().indexOf(text) > -1);
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
public static compareByField(a: any, b: any, fieldName: string): number {
|
||||
if (a && !b) {
|
||||
return 1;
|
||||
@@ -702,6 +713,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
if (!this.isEnabled()) {
|
||||
throw new Error('No extension gallery service configured.');
|
||||
}
|
||||
|
||||
// Always exclude non validated and unpublished extensions
|
||||
query = query
|
||||
.withFlags(query.flags, Flags.ExcludeNonValidated)
|
||||
@@ -717,34 +729,56 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
'Content-Length': String(data.length)
|
||||
};
|
||||
|
||||
const context = await this.requestService.request({
|
||||
// {{SQL CARBON EDIT}}
|
||||
type: 'GET',
|
||||
url: this.api('/extensionquery'),
|
||||
data,
|
||||
headers
|
||||
}, token);
|
||||
const startTime = new Date().getTime();
|
||||
let context: IRequestContext | undefined, error: any, total: number = 0;
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
let extensionPolicy: string = this.configurationService.getValue<string>(ExtensionsPolicyKey);
|
||||
if (context.res.statusCode && context.res.statusCode >= 400 && context.res.statusCode < 500 || extensionPolicy === ExtensionsPolicy.allowNone) {
|
||||
return { galleryExtensions: [], total: 0 };
|
||||
}
|
||||
|
||||
const result = await asJson<IRawGalleryQueryResult>(context);
|
||||
if (result) {
|
||||
const r = result.results[0];
|
||||
const galleryExtensions = r.extensions;
|
||||
// const resultCount = r.resultMetadata && r.resultMetadata.filter(m => m.metadataType === 'ResultCount')[0]; {{SQL CARBON EDIT}} comment out for no unused
|
||||
// const total = resultCount && resultCount.metadataItems.filter(i => i.name === 'TotalCount')[0].count || 0; {{SQL CARBON EDIT}} comment out for no unused
|
||||
try {
|
||||
context = await this.requestService.request({
|
||||
// {{SQL CARBON EDIT}}
|
||||
type: 'GET',
|
||||
url: this.api('/extensionquery'),
|
||||
data,
|
||||
headers
|
||||
}, token);
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
let filteredExtensionsResult = this.createQueryResult(query, galleryExtensions);
|
||||
let extensionPolicy: string = this.configurationService.getValue<string>(ExtensionsPolicyKey);
|
||||
if (context.res.statusCode && context.res.statusCode >= 400 && context.res.statusCode < 500 || extensionPolicy === ExtensionsPolicy.allowNone) {
|
||||
return { galleryExtensions: [], total: 0 };
|
||||
}
|
||||
|
||||
return { galleryExtensions: filteredExtensionsResult.galleryExtensions, total: filteredExtensionsResult.total };
|
||||
// {{SQL CARBON EDIT}} - End
|
||||
const result = await asJson<IRawGalleryQueryResult>(context);
|
||||
if (result) {
|
||||
const r = result.results[0];
|
||||
const galleryExtensions = r.extensions;
|
||||
// const resultCount = r.resultMetadata && r.resultMetadata.filter(m => m.metadataType === 'ResultCount')[0]; {{SQL CARBON EDIT}} comment out for no unused
|
||||
// const total = resultCount && resultCount.metadataItems.filter(i => i.name === 'TotalCount')[0].count || 0; {{SQL CARBON EDIT}} comment out for no unused
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
let filteredExtensionsResult = this.createQueryResult(query, galleryExtensions);
|
||||
|
||||
return { galleryExtensions: filteredExtensionsResult.galleryExtensions, total: filteredExtensionsResult.total };
|
||||
// {{SQL CARBON EDIT}} - End
|
||||
}
|
||||
return { galleryExtensions: [], total };
|
||||
|
||||
} catch (e) {
|
||||
error = e;
|
||||
throw e;
|
||||
} finally {
|
||||
this.telemetryService.publicLog2<GalleryServiceQueryEvent, GalleryServiceQueryClassification>('galleryService:query', {
|
||||
...query.telemetryData,
|
||||
requestBodySize: String(data.length),
|
||||
duration: new Date().getTime() - startTime,
|
||||
success: !!context && isSuccess(context),
|
||||
responseBodySize: context?.res.headers['Content-Length'],
|
||||
statusCode: context ? String(context.res.statusCode) : undefined,
|
||||
errorCode: error
|
||||
? isPromiseCanceledError(error) ? 'canceled' : getErrorMessage(error).startsWith('XHR timeout') ? 'timeout' : 'failed'
|
||||
: undefined,
|
||||
count: String(total)
|
||||
});
|
||||
}
|
||||
return { galleryExtensions: [], total: 0 };
|
||||
}
|
||||
|
||||
async reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void> {
|
||||
@@ -848,7 +882,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
try {
|
||||
engine = await this.getEngine(v);
|
||||
} catch (error) { /* Ignore error and skip version */ }
|
||||
if (engine && isEngineValid(engine, this.productService.version)) {
|
||||
if (engine && isEngineValid(engine, this.productService.version, this.productService.date)) {
|
||||
result.push({ version: v!.version, date: v!.lastUpdated });
|
||||
}
|
||||
}));
|
||||
@@ -914,8 +948,8 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
if (!vsCodeEngine && !azDataEngine) {
|
||||
return null;
|
||||
}
|
||||
const vsCodeEngineValid = !vsCodeEngine || (vsCodeEngine && isEngineValid(vsCodeEngine, this.productService.vscodeVersion));
|
||||
const azDataEngineValid = !azDataEngine || (azDataEngine && isEngineValid(azDataEngine, this.productService.version));
|
||||
const vsCodeEngineValid = !vsCodeEngine || (vsCodeEngine && isEngineValid(vsCodeEngine, this.productService.vscodeVersion, this.productService.date));
|
||||
const azDataEngineValid = !azDataEngine || (azDataEngine && isEngineValid(azDataEngine, this.productService.version, this.productService.date));
|
||||
if (vsCodeEngineValid && azDataEngineValid) {
|
||||
return version;
|
||||
}
|
||||
@@ -951,13 +985,14 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
|
||||
const version = versions[0];
|
||||
const engine = await this.getEngine(version);
|
||||
if (!isEngineValid(engine, this.productService.version)) {
|
||||
if (!isEngineValid(engine, this.productService.version, this.productService.date)) {
|
||||
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1));
|
||||
}
|
||||
|
||||
version.properties = version.properties || [];
|
||||
version.properties.push({ key: PropertyType.Engine, value: engine });
|
||||
return version;
|
||||
return {
|
||||
...version,
|
||||
properties: [...(version.properties || []), { key: PropertyType.Engine, value: engine }]
|
||||
};
|
||||
}
|
||||
|
||||
async getExtensionsReport(): Promise<IReportedExtension[]> {
|
||||
|
||||
@@ -207,6 +207,7 @@ export class ExtensionManagementError extends Error {
|
||||
}
|
||||
|
||||
export type InstallOptions = { isBuiltin?: boolean, isMachineScoped?: boolean, donotIncludePackAndDependencies?: boolean };
|
||||
export type InstallVSIXOptions = InstallOptions & { installOnlyNewlyAddedFromExtensionPack?: boolean };
|
||||
export type UninstallOptions = { donotIncludePack?: boolean, donotCheckDependents?: boolean };
|
||||
|
||||
export const IExtensionManagementService = createDecorator<IExtensionManagementService>('extensionManagementService');
|
||||
@@ -221,7 +222,7 @@ export interface IExtensionManagementService {
|
||||
zip(extension: ILocalExtension): Promise<URI>;
|
||||
unzip(zipLocation: URI): Promise<IExtensionIdentifier>;
|
||||
getManifest(vsix: URI): Promise<IExtensionManifest>;
|
||||
install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension>;
|
||||
install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension>;
|
||||
canInstall(extension: IGalleryExtension): Promise<boolean>;
|
||||
installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise<ILocalExtension>;
|
||||
uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise<void>;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionTipsService, InstallOptions, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionTipsService, InstallOptions, UninstallOptions, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
|
||||
@@ -62,7 +62,7 @@ export class ExtensionManagementChannel implements IServerChannel {
|
||||
switch (command) {
|
||||
case 'zip': return this.service.zip(transformIncomingExtension(args[0], uriTransformer)).then(uri => transformOutgoingURI(uri, uriTransformer));
|
||||
case 'unzip': return this.service.unzip(transformIncomingURI(args[0], uriTransformer));
|
||||
case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer));
|
||||
case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer), args[1]);
|
||||
case 'getManifest': return this.service.getManifest(transformIncomingURI(args[0], uriTransformer));
|
||||
case 'canInstall': return this.service.canInstall(args[0]);
|
||||
case 'installFromGallery': return this.service.installFromGallery(args[0], args[1]);
|
||||
@@ -112,8 +112,8 @@ export class ExtensionManagementChannelClient extends Disposable implements IExt
|
||||
return Promise.resolve(this.channel.call('unzip', [zipLocation]));
|
||||
}
|
||||
|
||||
install(vsix: URI): Promise<ILocalExtension> {
|
||||
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix])).then(local => transformIncomingExtension(local, null));
|
||||
install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension> {
|
||||
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix, options])).then(local => transformIncomingExtension(local, null));
|
||||
}
|
||||
|
||||
getManifest(vsix: URI): Promise<IExtensionManifest> {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { promises } from 'fs';
|
||||
import { Promises as FSPromises } from 'vs/base/node/pfs';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files';
|
||||
import { IExtensionGalleryService, IGalleryExtension, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
@@ -77,7 +77,7 @@ export class ExtensionsDownloader extends Disposable {
|
||||
|
||||
private async rename(from: URI, to: URI, retryUntil: number): Promise<void> {
|
||||
try {
|
||||
await promises.rename(from.fsPath, to.fsPath);
|
||||
await FSPromises.rename(from.fsPath, to.fsPath);
|
||||
} catch (error) {
|
||||
if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) {
|
||||
this.logService.info(`Failed renaming ${from} to ${to} with 'EPERM' error. Trying again...`);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { join } from 'vs/base/common/path';
|
||||
import { Limiter } from 'vs/base/common/async';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { rimraf } from 'vs/base/node/pfs';
|
||||
import { Promises } from 'vs/base/node/pfs';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export class ExtensionsLifecycle extends Disposable {
|
||||
@@ -34,7 +34,7 @@ export class ExtensionsLifecycle extends Disposable {
|
||||
this.runLifecycleHook(script.script, 'uninstall', script.args, true, extension)
|
||||
.then(() => this.logService.info(extension.identifier.id, extension.manifest.version, `Finished running post uninstall script`), err => this.logService.error(extension.identifier.id, extension.manifest.version, `Failed to run post uninstall script: ${err}`)));
|
||||
}
|
||||
return rimraf(this.getExtensionStoragePath(extension)).then(undefined, e => this.logService.error('Error while removing extension storage path', e));
|
||||
return Promises.rm(this.getExtensionStoragePath(extension)).then(undefined, e => this.logService.error('Error while removing extension storage path', e));
|
||||
}
|
||||
|
||||
private parseScript(extension: ILocalExtension, type: string): { script: string, args: string[] } | null {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { toDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
// import { isNonEmptyArray } from 'vs/base/common/arrays'; {{SQL CARBON EDIT}}
|
||||
import { zip, IFile } from 'vs/base/node/zip';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, ILocalExtension,
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
INSTALL_ERROR_INCOMPATIBLE,
|
||||
ExtensionManagementError,
|
||||
InstallOptions,
|
||||
UninstallOptions
|
||||
UninstallOptions,
|
||||
InstallVSIXOptions
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions, getGalleryExtensionId, getMaliciousExtensionsSet, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
@@ -137,9 +138,9 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
private async collectFiles(extension: ILocalExtension): Promise<IFile[]> {
|
||||
|
||||
const collectFilesFromDirectory = async (dir: string): Promise<string[]> => {
|
||||
let entries = await pfs.readdir(dir);
|
||||
let entries = await pfs.Promises.readdir(dir);
|
||||
entries = entries.map(e => path.join(dir, e));
|
||||
const stats = await Promise.all(entries.map(e => fs.promises.stat(e)));
|
||||
const stats = await Promise.all(entries.map(e => pfs.Promises.stat(e)));
|
||||
let promise: Promise<string[]> = Promise.resolve([]);
|
||||
stats.forEach((stat, index) => {
|
||||
const entry = entries[index];
|
||||
@@ -159,7 +160,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
return files.map(f => (<IFile>{ path: `extension/${path.relative(extension.location.fsPath, f)}`, localPath: f }));
|
||||
}
|
||||
|
||||
async install(vsix: URI, options: InstallOptions = {}): Promise<ILocalExtension> {
|
||||
async install(vsix: URI, options: InstallVSIXOptions = {}): Promise<ILocalExtension> {
|
||||
// {{SQL CARBON EDIT}}
|
||||
let startTime = new Date().getTime();
|
||||
this.logService.trace('ExtensionManagementService#install', vsix.toString());
|
||||
@@ -172,10 +173,10 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
|
||||
// let operation: InstallOperation = InstallOperation.Install; {{SQL CARBON EDIT}}
|
||||
// {{SQL CARBON EDIT}}
|
||||
if (manifest.engines?.vscode && !isEngineValid(manifest.engines.vscode, product.vscodeVersion)) {
|
||||
if (manifest.engines?.vscode && !isEngineValid(manifest.engines.vscode, product.vscodeVersion, product.date)) {
|
||||
throw new Error(nls.localize('incompatible', "Unable to install extension '{0}' as it is not compatible with the current VS Code engine version '{1}'.", identifier.id, product.vscodeVersion));
|
||||
}
|
||||
if (manifest.engines?.azdata && !isEngineValid(manifest.engines.azdata, product.version)) {
|
||||
if (manifest.engines?.azdata && !isEngineValid(manifest.engines.azdata, product.version, product.date)) {
|
||||
throw new Error(nls.localize('incompatibleAzdata', "Unable to install extension '{0}' as it is not compatible with Azure Data Studio '{1}'.", identifier.id, product.version));
|
||||
}
|
||||
|
||||
@@ -228,8 +229,9 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
// try {
|
||||
// metadata = await this.getGalleryMetadata(getGalleryExtensionId(manifest.publisher, manifest.name));
|
||||
// } catch (e) { /* Ignore */ }
|
||||
|
||||
// try {
|
||||
// const local = await this.installFromZipPath(identifierWithVersion, zipPath, isMachineScoped ? { ...(metadata || {}), isMachineScoped } : metadata, operation, token);
|
||||
// const local = await this.installFromZipPath(identifierWithVersion, zipPath, options.installOnlyNewlyAddedFromExtensionPack ? existing : undefined, { ...(metadata || {}), ...options }, options, operation, token);
|
||||
// this.logService.info('Successfully installed the extension:', identifier.id);
|
||||
// return local;
|
||||
// } catch (e) {
|
||||
@@ -253,11 +255,13 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
/*private async installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, metadata: IMetadata | undefined, operation: InstallOperation, token: CancellationToken): Promise<ILocalExtension> {
|
||||
/*private async installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, existing: ILocalExtension | undefined, metadata: IMetadata | undefined, options: InstallOptions, operation: InstallOperation, token: CancellationToken): Promise<ILocalExtension> {
|
||||
try {
|
||||
const local = await this.installExtension({ zipPath, identifierWithVersion, metadata }, token);
|
||||
try {
|
||||
await this.installDependenciesAndPackExtensions(local, undefined, options);
|
||||
if (!options.donotIncludePackAndDependencies) {
|
||||
await this.installDependenciesAndPackExtensions(local, existing, options);
|
||||
}
|
||||
} catch (error) {
|
||||
if (isNonEmptyArray(local.manifest.extensionDependencies)) {
|
||||
this.logService.warn(`Cannot install dependencies of extension:`, local.identifier.id, error.message);
|
||||
@@ -657,7 +661,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
}
|
||||
|
||||
private async preUninstallExtension(extension: ILocalExtension): Promise<void> {
|
||||
const exists = await pfs.exists(extension.location.fsPath);
|
||||
const exists = await pfs.Promises.exists(extension.location.fsPath);
|
||||
if (!exists) {
|
||||
throw new Error(nls.localize('notExists', "Could not find extension"));
|
||||
}
|
||||
|
||||
@@ -16,4 +16,4 @@ export function getManifest(vsix: string): Promise<IExtensionManifest> {
|
||||
throw new Error(localize('invalidManifest', "VSIX invalid: package.json is not a JSON file."));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@ export class ExtensionsManifestCache extends Disposable {
|
||||
}
|
||||
|
||||
invalidate(): void {
|
||||
pfs.rimraf(this.extensionsManifestCache, pfs.RimRafMode.MOVE).then(() => { }, () => { });
|
||||
pfs.Promises.rm(this.extensionsManifestCache, pfs.RimRafMode.MOVE).then(() => { }, () => { });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as semver from 'vs/base/common/semver/semver';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
@@ -107,10 +106,10 @@ export class ExtensionsScanner extends Disposable {
|
||||
const extensionPath = path.join(this.extensionsPath, folderName);
|
||||
|
||||
try {
|
||||
await pfs.rimraf(extensionPath);
|
||||
await pfs.Promises.rm(extensionPath);
|
||||
} catch (error) {
|
||||
try {
|
||||
await pfs.rimraf(extensionPath);
|
||||
await pfs.Promises.rm(extensionPath);
|
||||
} catch (e) { /* ignore */ }
|
||||
throw new ExtensionManagementError(localize('errorDeleting', "Unable to delete the existing folder '{0}' while installing the extension '{1}'. Please delete the folder manually and try again", extensionPath, identifierWithVersion.id), INSTALL_ERROR_DELETING);
|
||||
}
|
||||
@@ -127,7 +126,7 @@ export class ExtensionsScanner extends Disposable {
|
||||
this.logService.info('Renamed to', extensionPath);
|
||||
} catch (error) {
|
||||
try {
|
||||
await pfs.rimraf(tempPath);
|
||||
await pfs.Promises.rm(tempPath);
|
||||
} catch (e) { /* ignore */ }
|
||||
if (error.code === 'ENOTEMPTY') {
|
||||
this.logService.info(`Rename failed because extension was installed by another source. So ignoring renaming.`, identifierWithVersion.id);
|
||||
@@ -159,10 +158,10 @@ export class ExtensionsScanner extends Disposable {
|
||||
storedMetadata.isBuiltin = storedMetadata.isBuiltin || undefined;
|
||||
storedMetadata.installedTimestamp = storedMetadata.installedTimestamp || undefined;
|
||||
const manifestPath = path.join(local.location.fsPath, 'package.json');
|
||||
const raw = await fs.promises.readFile(manifestPath, 'utf8');
|
||||
const raw = await pfs.Promises.readFile(manifestPath, 'utf8');
|
||||
const { manifest } = await this.parseManifest(raw);
|
||||
(manifest as ILocalExtensionManifest).__metadata = storedMetadata;
|
||||
await pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'));
|
||||
await pfs.Promises.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'));
|
||||
return local;
|
||||
}
|
||||
|
||||
@@ -192,7 +191,7 @@ export class ExtensionsScanner extends Disposable {
|
||||
return this.uninstalledFileLimiter.queue(async () => {
|
||||
let raw: string | undefined;
|
||||
try {
|
||||
raw = await fs.promises.readFile(this.uninstalledPath, 'utf8');
|
||||
raw = await pfs.Promises.readFile(this.uninstalledPath, 'utf8');
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
@@ -209,9 +208,9 @@ export class ExtensionsScanner extends Disposable {
|
||||
if (updateFn) {
|
||||
updateFn(uninstalled);
|
||||
if (Object.keys(uninstalled).length) {
|
||||
await pfs.writeFile(this.uninstalledPath, JSON.stringify(uninstalled));
|
||||
await pfs.Promises.writeFile(this.uninstalledPath, JSON.stringify(uninstalled));
|
||||
} else {
|
||||
await pfs.rimraf(this.uninstalledPath);
|
||||
await pfs.Promises.rm(this.uninstalledPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +220,7 @@ export class ExtensionsScanner extends Disposable {
|
||||
|
||||
async removeExtension(extension: ILocalExtension, type: string): Promise<void> {
|
||||
this.logService.trace(`Deleting ${type} extension from disk`, extension.identifier.id, extension.location.fsPath);
|
||||
await pfs.rimraf(extension.location.fsPath);
|
||||
await pfs.Promises.rm(extension.location.fsPath);
|
||||
this.logService.info('Deleted from disk', extension.identifier.id, extension.location.fsPath);
|
||||
}
|
||||
|
||||
@@ -235,7 +234,7 @@ export class ExtensionsScanner extends Disposable {
|
||||
|
||||
// Clean the location
|
||||
try {
|
||||
await pfs.rimraf(location);
|
||||
await pfs.Promises.rm(location);
|
||||
} catch (e) {
|
||||
throw new ExtensionManagementError(this.joinErrors(e).message, INSTALL_ERROR_DELETING);
|
||||
}
|
||||
@@ -244,14 +243,14 @@ export class ExtensionsScanner extends Disposable {
|
||||
await extract(zipPath, location, { sourcePath: 'extension', overwrite: true }, token);
|
||||
this.logService.info(`Extracted extension to ${location}:`, identifier.id);
|
||||
} catch (e) {
|
||||
try { await pfs.rimraf(location); } catch (e) { /* Ignore */ }
|
||||
try { await pfs.Promises.rm(location); } catch (e) { /* Ignore */ }
|
||||
throw new ExtensionManagementError(e.message, e instanceof ExtractError && e.type ? e.type : INSTALL_ERROR_EXTRACTING);
|
||||
}
|
||||
}
|
||||
|
||||
private async rename(identifier: IExtensionIdentifier, extractPath: string, renamePath: string, retryUntil: number): Promise<void> {
|
||||
try {
|
||||
await fs.promises.rename(extractPath, renamePath);
|
||||
await pfs.Promises.rename(extractPath, renamePath);
|
||||
} catch (error) {
|
||||
if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) {
|
||||
this.logService.info(`Failed renaming ${extractPath} to ${renamePath} with 'EPERM' error. Trying again...`, identifier.id);
|
||||
@@ -393,9 +392,9 @@ export class ExtensionsScanner extends Disposable {
|
||||
|
||||
private async readManifest(extensionPath: string): Promise<{ manifest: IExtensionManifest; metadata: IStoredMetadata | null; }> {
|
||||
const promises = [
|
||||
fs.promises.readFile(path.join(extensionPath, 'package.json'), 'utf8')
|
||||
pfs.Promises.readFile(path.join(extensionPath, 'package.json'), 'utf8')
|
||||
.then(raw => this.parseManifest(raw)),
|
||||
fs.promises.readFile(path.join(extensionPath, 'package.nls.json'), 'utf8')
|
||||
pfs.Promises.readFile(path.join(extensionPath, 'package.nls.json'), 'utf8')
|
||||
.then(undefined, err => err.code !== 'ENOENT' ? Promise.reject<string>(err) : '{}')
|
||||
.then(raw => JSON.parse(raw))
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
Reference in New Issue
Block a user