in src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts [567:787]
private async resolveWorkspaceTags(): Promise<Tags> {
const tags: Tags = Object.create(null);
const state = this.contextService.getWorkbenchState();
const workspace = this.contextService.getWorkspace();
tags['workspace.id'] = await this.getTelemetryWorkspaceId(workspace, state);
const { filesToOpenOrCreate, filesToDiff } = this.environmentService.configuration;
tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0;
tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0;
const isEmpty = state === WorkbenchState.EMPTY;
tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length;
tags['workspace.empty'] = isEmpty;
const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.productService.quality !== 'stable' && this.findFolders();
if (!folders || !folders.length) {
return Promise.resolve(tags);
}
return this.fileService.resolveAll(folders.map(resource => ({ resource }))).then((files: IResolveFileResult[]) => {
const names = (<IFileStat[]>[]).concat(...files.map(result => result.success ? (result.stat!.children || []) : [])).map(c => c.name);
const nameSet = names.reduce((s, n) => s.add(n.toLowerCase()), new Set());
tags['workspace.grunt'] = nameSet.has('gruntfile.js');
tags['workspace.gulp'] = nameSet.has('gulpfile.js');
tags['workspace.jake'] = nameSet.has('jakefile.js');
tags['workspace.tsconfig'] = nameSet.has('tsconfig.json');
tags['workspace.jsconfig'] = nameSet.has('jsconfig.json');
tags['workspace.config.xml'] = nameSet.has('config.xml');
tags['workspace.vsc.extension'] = nameSet.has('vsc-extension-quickstart.md');
tags['workspace.ASP5'] = nameSet.has('project.json') && this.searchArray(names, /^.+\.cs$/i);
tags['workspace.sln'] = this.searchArray(names, /^.+\.sln$|^.+\.csproj$/i);
tags['workspace.unity'] = nameSet.has('assets') && nameSet.has('library') && nameSet.has('projectsettings');
tags['workspace.npm'] = nameSet.has('package.json') || nameSet.has('node_modules');
tags['workspace.bower'] = nameSet.has('bower.json') || nameSet.has('bower_components');
tags['workspace.java.pom'] = nameSet.has('pom.xml');
tags['workspace.java.gradle'] = nameSet.has('build.gradle') || nameSet.has('settings.gradle');
tags['workspace.yeoman.code.ext'] = nameSet.has('vsc-extension-quickstart.md');
tags['workspace.py.requirements'] = nameSet.has('requirements.txt');
tags['workspace.py.requirements.star'] = this.searchArray(names, /^(.*)requirements(.*)\.txt$/i);
tags['workspace.py.Pipfile'] = nameSet.has('pipfile');
tags['workspace.py.conda'] = this.searchArray(names, /^environment(\.yml$|\.yaml$)/i);
const mainActivity = nameSet.has('mainactivity.cs') || nameSet.has('mainactivity.fs');
const appDelegate = nameSet.has('appdelegate.cs') || nameSet.has('appdelegate.fs');
const androidManifest = nameSet.has('androidmanifest.xml');
const platforms = nameSet.has('platforms');
const plugins = nameSet.has('plugins');
const www = nameSet.has('www');
const properties = nameSet.has('properties');
const resources = nameSet.has('resources');
const jni = nameSet.has('jni');
if (tags['workspace.config.xml'] &&
!tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) {
if (platforms && plugins && www) {
tags['workspace.cordova.high'] = true;
} else {
tags['workspace.cordova.low'] = true;
}
}
if (tags['workspace.config.xml'] &&
!tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) {
if (nameSet.has('ionic.config.json')) {
tags['workspace.ionic'] = true;
}
}
if (mainActivity && properties && resources) {
tags['workspace.xamarin.android'] = true;
}
if (appDelegate && resources) {
tags['workspace.xamarin.ios'] = true;
}
if (androidManifest && jni) {
tags['workspace.android.cpp'] = true;
}
function getFilePromises(filename: string, fileService: IFileService, textFileService: ITextFileService, contentHandler: (content: ITextFileContent) => void): Promise<void>[] {
return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => {
const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` });
return fileService.exists(uri).then(exists => {
if (!exists) {
return undefined;
}
return textFileService.read(uri, { acceptTextOnly: true }).then(contentHandler);
}, err => {
// Ignore missing file
});
});
}
function addPythonTags(packageName: string): void {
if (PyModulesToLookFor.indexOf(packageName) > -1) {
tags['workspace.py.' + packageName] = true;
}
for (const metaModule of PyMetaModulesToLookFor) {
if (packageName.startsWith(metaModule)) {
tags['workspace.py.' + metaModule] = true;
}
}
if (!tags['workspace.py.any-azure']) {
tags['workspace.py.any-azure'] = /azure/i.test(packageName);
}
}
const requirementsTxtPromises = getFilePromises('requirements.txt', this.fileService, this.textFileService, content => {
const dependencies: string[] = splitLines(content.value);
for (let dependency of dependencies) {
// Dependencies in requirements.txt can have 3 formats: `foo==3.1, foo>=3.1, foo`
const format1 = dependency.split('==');
const format2 = dependency.split('>=');
const packageName = (format1.length === 2 ? format1[0] : format2[0]).trim();
addPythonTags(packageName);
}
});
const pipfilePromises = getFilePromises('pipfile', this.fileService, this.textFileService, content => {
let dependencies: string[] = splitLines(content.value);
// We're only interested in the '[packages]' section of the Pipfile
dependencies = dependencies.slice(dependencies.indexOf('[packages]') + 1);
for (let dependency of dependencies) {
if (dependency.trim().indexOf('[') > -1) {
break;
}
// All dependencies in Pipfiles follow the format: `<package> = <version, or git repo, or something else>`
if (dependency.indexOf('=') === -1) {
continue;
}
const packageName = dependency.split('=')[0].trim();
addPythonTags(packageName);
}
});
const packageJsonPromises = getFilePromises('package.json', this.fileService, this.textFileService, content => {
try {
const packageJsonContents = JSON.parse(content.value);
let dependencies = Object.keys(packageJsonContents['dependencies'] || {}).concat(Object.keys(packageJsonContents['devDependencies'] || {}));
for (let dependency of dependencies) {
if (dependency.startsWith('react-native')) {
tags['workspace.reactNative'] = true;
} else if ('tns-core-modules' === dependency || '@nativescript/core' === dependency) {
tags['workspace.nativescript'] = true;
} else if (ModulesToLookFor.indexOf(dependency) > -1) {
tags['workspace.npm.' + dependency] = true;
} else {
for (const metaModule of MetaModulesToLookFor) {
if (dependency.startsWith(metaModule)) {
tags['workspace.npm.' + metaModule] = true;
}
}
}
}
}
catch (e) {
// Ignore errors when resolving file or parsing file contents
}
});
const pomPromises = getFilePromises('pom.xml', this.fileService, this.textFileService, content => {
try {
let dependenciesContent;
while (dependenciesContent = MavenDependenciesRegex.exec(content.value)) {
let dependencyContent;
while (dependencyContent = MavenDependencyRegex.exec(dependenciesContent[1])) {
const groupIdContent = MavenGroupIdRegex.exec(dependencyContent[1]);
const artifactIdContent = MavenArtifactIdRegex.exec(dependencyContent[1]);
if (groupIdContent && artifactIdContent) {
this.tagJavaDependency(groupIdContent[1], artifactIdContent[1], 'workspace.pom.', tags);
}
}
}
}
catch (e) {
// Ignore errors when resolving maven dependencies
}
});
const gradlePromises = getFilePromises('build.gradle', this.fileService, this.textFileService, content => {
try {
this.processGradleDependencies(content.value, GradleDependencyLooseRegex, tags);
this.processGradleDependencies(content.value, GradleDependencyCompactRegex, tags);
}
catch (e) {
// Ignore errors when resolving gradle dependencies
}
});
const androidPromises = folders.map(workspaceUri => {
const manifest = URI.joinPath(workspaceUri, '/app/src/main/AndroidManifest.xml');
return this.fileService.exists(manifest).then(result => {
if (result) {
tags['workspace.java.android'] = true;
}
}, err => {
// Ignore errors when resolving android
});
});
return Promise.all([...packageJsonPromises, ...requirementsTxtPromises, ...pipfilePromises, ...pomPromises, ...gradlePromises, ...androidPromises]).then(() => tags);
});
}