Path: blob/main/src/vs/workbench/services/extensions/common/workspaceContains.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as resources from '../../../../base/common/resources.js';6import { URI, UriComponents } from '../../../../base/common/uri.js';7import { CancellationTokenSource, CancellationToken } from '../../../../base/common/cancellation.js';8import * as errors from '../../../../base/common/errors.js';9import { ExtensionIdentifier, IExtensionDescription } from '../../../../platform/extensions/common/extensions.js';10import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';11import { QueryBuilder } from '../../search/common/queryBuilder.js';12import { ISearchService } from '../../search/common/search.js';13import { toWorkspaceFolder } from '../../../../platform/workspace/common/workspace.js';14import { ILogService } from '../../../../platform/log/common/log.js';15import { promiseWithResolvers } from '../../../../base/common/async.js';1617const WORKSPACE_CONTAINS_TIMEOUT = 7000;1819export interface IExtensionActivationHost {20readonly logService: ILogService;21readonly folders: readonly UriComponents[];22readonly forceUsingSearch: boolean;2324exists(uri: URI): Promise<boolean>;25checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;26}2728export interface IExtensionActivationResult {29activationEvent: string;30}3132export function checkActivateWorkspaceContainsExtension(host: IExtensionActivationHost, desc: IExtensionDescription): Promise<IExtensionActivationResult | undefined> {33const activationEvents = desc.activationEvents;34if (!activationEvents) {35return Promise.resolve(undefined);36}3738const fileNames: string[] = [];39const globPatterns: string[] = [];4041for (const activationEvent of activationEvents) {42if (/^workspaceContains:/.test(activationEvent)) {43const fileNameOrGlob = activationEvent.substr('workspaceContains:'.length);44if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0 || host.forceUsingSearch) {45globPatterns.push(fileNameOrGlob);46} else {47fileNames.push(fileNameOrGlob);48}49}50}5152if (fileNames.length === 0 && globPatterns.length === 0) {53return Promise.resolve(undefined);54}5556const { promise, resolve } = promiseWithResolvers<IExtensionActivationResult | undefined>();57const activate = (activationEvent: string) => resolve({ activationEvent });5859const fileNamePromise = Promise.all(fileNames.map((fileName) => _activateIfFileName(host, fileName, activate))).then(() => { });60const globPatternPromise = _activateIfGlobPatterns(host, desc.identifier, globPatterns, activate);6162Promise.all([fileNamePromise, globPatternPromise]).then(() => {63// when all are done, resolve with undefined (relevant only if it was not activated so far)64resolve(undefined);65});6667return promise;68}6970async function _activateIfFileName(host: IExtensionActivationHost, fileName: string, activate: (activationEvent: string) => void): Promise<void> {71// find exact path72for (const uri of host.folders) {73if (await host.exists(resources.joinPath(URI.revive(uri), fileName))) {74// the file was found75activate(`workspaceContains:${fileName}`);76return;77}78}79}8081async function _activateIfGlobPatterns(host: IExtensionActivationHost, extensionId: ExtensionIdentifier, globPatterns: string[], activate: (activationEvent: string) => void): Promise<void> {82if (globPatterns.length === 0) {83return Promise.resolve(undefined);84}8586const tokenSource = new CancellationTokenSource();87const searchP = host.checkExists(host.folders, globPatterns, tokenSource.token);8889const timer = setTimeout(async () => {90tokenSource.cancel();91host.logService.info(`Not activating extension '${extensionId.value}': Timed out while searching for 'workspaceContains' pattern ${globPatterns.join(',')}`);92}, WORKSPACE_CONTAINS_TIMEOUT);9394let exists: boolean = false;95try {96exists = await searchP;97} catch (err) {98if (!errors.isCancellationError(err)) {99errors.onUnexpectedError(err);100}101}102103tokenSource.dispose();104clearTimeout(timer);105106if (exists) {107// a file was found matching one of the glob patterns108activate(`workspaceContains:${globPatterns.join(',')}`);109}110}111112export function checkGlobFileExists(113accessor: ServicesAccessor,114folders: readonly UriComponents[],115includes: string[],116token: CancellationToken,117): Promise<boolean> {118const instantiationService = accessor.get(IInstantiationService);119const searchService = accessor.get(ISearchService);120const queryBuilder = instantiationService.createInstance(QueryBuilder);121const query = queryBuilder.file(folders.map(folder => toWorkspaceFolder(URI.revive(folder))), {122_reason: 'checkExists',123includePattern: includes,124exists: true125});126127return searchService.fileSearch(query, token).then(128result => {129return !!result.limitHit;130},131err => {132if (!errors.isCancellationError(err)) {133return Promise.reject(err);134}135136return false;137});138}139140141