Skip to content

Commit

Permalink
Make collectWorkspaceStats asynchronous, fixes #45163
Browse files Browse the repository at this point in the history
  • Loading branch information
Rachel Macfarlane committed May 2, 2018
1 parent e4e7c25 commit 220bf36
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 66 deletions.
133 changes: 87 additions & 46 deletions src/vs/base/node/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

'use strict';

import { readdirSync, statSync, existsSync, readFileSync } from 'fs';
import { readdir, stat, exists, readFile } from 'fs';
import { join } from 'path';

export interface WorkspaceStatItem {
Expand All @@ -26,34 +26,43 @@ function asSortedItems(map: Map<string, number>): WorkspaceStatItem[] {
return a.sort((a, b) => b.count - a.count);
}

export function collectLaunchConfigs(folder: string): WorkspaceStatItem[] {
export function collectLaunchConfigs(folder: string): Promise<WorkspaceStatItem[]> {
let launchConfigs = new Map<string, number>();

let launchConfig = join(folder, '.vscode', 'launch.json');
if (existsSync(launchConfig)) {
try {
const contents = readFileSync(launchConfig).toString();
const json = JSON.parse(contents);
if (json['configurations']) {
for (const each of json['configurations']) {
const type = each['type'];
if (type) {
if (launchConfigs.has(type)) {
launchConfigs.set(type, launchConfigs.get(type) + 1);
}
else {
launchConfigs.set(type, 1);
return new Promise((resolve, reject) => {
exists(launchConfig, (doesExist) => {
if (doesExist) {
readFile(launchConfig, (err, contents) => {
if (err) {
return resolve([]);
}

const json = JSON.parse(contents.toString());
if (json['configurations']) {
for (const each of json['configurations']) {
const type = each['type'];
if (type) {
if (launchConfigs.has(type)) {
launchConfigs.set(type, launchConfigs.get(type) + 1);
}
else {
launchConfigs.set(type, 1);
}
}
}
}
}

return resolve(asSortedItems(launchConfigs));
});
} else {
return resolve([]);
}
} catch {
}
}
return asSortedItems(launchConfigs);
});
});
}

export function collectWorkspaceStats(folder: string, filter: string[]): WorkspaceStats {
export function collectWorkspaceStats(folder: string, filter: string[]): Promise<WorkspaceStats> {
const configFilePatterns = [
{ 'tag': 'grunt.js', 'pattern': /^gruntfile\.js$/i },
{ 'tag': 'gulp.js', 'pattern': /^gulpfile\.js$/i },
Expand All @@ -78,35 +87,62 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Workspa

const MAX_FILES = 20000;

let walkSync = (dir: string, acceptFile: (fileName: string) => void, filter: string[], token) => {
try {
let files = readdirSync(dir);
function walk(dir: string, filter: string[], token, done: (allFiles: string[]) => void): void {
let results = [];
readdir(dir, async (err, files) => {
// Ignore folders that can't be read
if (err) {
return done(results);
}

let pending = files.length;
if (pending === 0) {
return done(results);
}

for (const file of files) {
if (token.maxReached) {
return;
return done(results);
}
try {
if (statSync(join(dir, file)).isDirectory()) {
if (filter.indexOf(file) === -1) {
walkSync(join(dir, file), acceptFile, filter, token);

stat(join(dir, file), (err, stats) => {
// Ignore files that can't be read
if (err) {
if (--pending === 0) {
return done(results);
}
}
else {

if (stats.isDirectory()) {
if (filter.indexOf(file) === -1) {
walk(join(dir, file), filter, token, (res: string[]) => {
results = results.concat(res);

if (--pending === 0) {
return done(results);
}
});
} else {
if (--pending === 0) {
done(results);
}
}
} else {
if (token.count >= MAX_FILES) {
token.maxReached = true;
return;
}

token.count++;
acceptFile(file);
results.push(file);

if (--pending === 0) {
done(results);
}
}
} catch {
// skip over files for which stat fails
}
});
}
} catch {
// skip over folders that cannot be read
}
};
});
}

let addFileType = (fileType: string) => {
if (fileTypes.has(fileType)) {
Expand Down Expand Up @@ -140,13 +176,18 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Workspa
};

let token: { count: number, maxReached: boolean } = { count: 0, maxReached: false };
walkSync(folder, acceptFile, filter, token);

return {
configFiles: asSortedItems(configFiles),
fileTypes: asSortedItems(fileTypes),
fileCount: token.count,
maxFilesReached: token.maxReached
return new Promise((resolve, reject) => {
walk(folder, filter, token, (files) => {
files.forEach(acceptFile);

};
resolve({
configFiles: asSortedItems(configFiles),
fileTypes: asSortedItems(fileTypes),
fileCount: token.count,
maxFilesReached: token.maxReached

});
});
});
}
50 changes: 30 additions & 20 deletions src/vs/code/electron-main/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export function getPerformanceInfo(info: IMainProcessInfo): Promise<PerformanceI
const workspaceInfoMessages = [];

// Workspace Stats
const workspaceStatPromises = [];
if (info.windows.some(window => window.folders && window.folders.length > 0)) {
info.windows.forEach(window => {
if (window.folders.length === 0) {
Expand All @@ -58,30 +59,35 @@ export function getPerformanceInfo(info: IMainProcessInfo): Promise<PerformanceI
workspaceInfoMessages.push(`| Window (${window.title})`);

window.folders.forEach(folder => {
try {
const stats = collectWorkspaceStats(folder, ['node_modules', '.git']);
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(async stats => {

let countMessage = `${stats.fileCount} files`;
if (stats.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
workspaceInfoMessages.push(`| Folder (${basename(folder)}): ${countMessage}`);
workspaceInfoMessages.push(formatWorkspaceStats(stats));

const launchConfigs = collectLaunchConfigs(folder);
const launchConfigs = await collectLaunchConfigs(folder);
if (launchConfigs.length > 0) {
workspaceInfoMessages.push(formatLaunchConfigs(launchConfigs));
}
} catch (error) {
workspaceInfoMessages.push(`| Error: Unable to collect workpsace stats for folder ${folder} (${error.toString()})`);
}
}));
});
});
}

return {
processInfo: formatProcessList(info, rootProcess),
workspaceInfo: workspaceInfoMessages.join('\n')
};
return Promise.all(workspaceStatPromises).then(() => {
return {
processInfo: formatProcessList(info, rootProcess),
workspaceInfo: workspaceInfoMessages.join('\n')
};
}).catch(error => {
return {
processInfo: formatProcessList(info, rootProcess),
workspaceInfo: `Unable to calculate workspace stats: ${error}`
};
});
});
}

Expand Down Expand Up @@ -122,6 +128,7 @@ export function printDiagnostics(info: IMainProcessInfo): Promise<any> {
console.log(formatProcessList(info, rootProcess));

// Workspace Stats
const workspaceStatPromises = [];
if (info.windows.some(window => window.folders && window.folders.length > 0)) {
console.log('');
console.log('Workspace Stats: ');
Expand All @@ -133,27 +140,30 @@ export function printDiagnostics(info: IMainProcessInfo): Promise<any> {
console.log(`| Window (${window.title})`);

window.folders.forEach(folder => {
try {
const stats = collectWorkspaceStats(folder, ['node_modules', '.git']);
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(async stats => {
let countMessage = `${stats.fileCount} files`;
if (stats.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
console.log(`| Folder (${basename(folder)}): ${countMessage}`);
console.log(formatWorkspaceStats(stats));

const launchConfigs = collectLaunchConfigs(folder);
if (launchConfigs.length > 0) {
console.log(formatLaunchConfigs(launchConfigs));
}
} catch (error) {
await collectLaunchConfigs(folder).then(launchConfigs => {
if (launchConfigs.length > 0) {
console.log(formatLaunchConfigs(launchConfigs));
}
});
}).catch(error => {
console.log(`| Error: Unable to collect workpsace stats for folder ${folder} (${error.toString()})`);
}
}));
});
});
}
console.log('');
console.log('');

return Promise.all(workspaceStatPromises).then(() => {
console.log('');
console.log('');
});
});
}

Expand Down

0 comments on commit 220bf36

Please sign in to comment.