Skip to content

Commit 220bf36

Browse files
author
Rachel Macfarlane
committed
Make collectWorkspaceStats asynchronous, fixes microsoft#45163
1 parent e4e7c25 commit 220bf36

2 files changed

Lines changed: 117 additions & 66 deletions

File tree

src/vs/base/node/stats.ts

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict';
77

8-
import { readdirSync, statSync, existsSync, readFileSync } from 'fs';
8+
import { readdir, stat, exists, readFile } from 'fs';
99
import { join } from 'path';
1010

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

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

3232
let launchConfig = join(folder, '.vscode', 'launch.json');
33-
if (existsSync(launchConfig)) {
34-
try {
35-
const contents = readFileSync(launchConfig).toString();
36-
const json = JSON.parse(contents);
37-
if (json['configurations']) {
38-
for (const each of json['configurations']) {
39-
const type = each['type'];
40-
if (type) {
41-
if (launchConfigs.has(type)) {
42-
launchConfigs.set(type, launchConfigs.get(type) + 1);
43-
}
44-
else {
45-
launchConfigs.set(type, 1);
33+
return new Promise((resolve, reject) => {
34+
exists(launchConfig, (doesExist) => {
35+
if (doesExist) {
36+
readFile(launchConfig, (err, contents) => {
37+
if (err) {
38+
return resolve([]);
39+
}
40+
41+
const json = JSON.parse(contents.toString());
42+
if (json['configurations']) {
43+
for (const each of json['configurations']) {
44+
const type = each['type'];
45+
if (type) {
46+
if (launchConfigs.has(type)) {
47+
launchConfigs.set(type, launchConfigs.get(type) + 1);
48+
}
49+
else {
50+
launchConfigs.set(type, 1);
51+
}
52+
}
4653
}
4754
}
48-
}
55+
56+
return resolve(asSortedItems(launchConfigs));
57+
});
58+
} else {
59+
return resolve([]);
4960
}
50-
} catch {
51-
}
52-
}
53-
return asSortedItems(launchConfigs);
61+
});
62+
});
5463
}
5564

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

7988
const MAX_FILES = 20000;
8089

81-
let walkSync = (dir: string, acceptFile: (fileName: string) => void, filter: string[], token) => {
82-
try {
83-
let files = readdirSync(dir);
90+
function walk(dir: string, filter: string[], token, done: (allFiles: string[]) => void): void {
91+
let results = [];
92+
readdir(dir, async (err, files) => {
93+
// Ignore folders that can't be read
94+
if (err) {
95+
return done(results);
96+
}
97+
98+
let pending = files.length;
99+
if (pending === 0) {
100+
return done(results);
101+
}
102+
84103
for (const file of files) {
85104
if (token.maxReached) {
86-
return;
105+
return done(results);
87106
}
88-
try {
89-
if (statSync(join(dir, file)).isDirectory()) {
90-
if (filter.indexOf(file) === -1) {
91-
walkSync(join(dir, file), acceptFile, filter, token);
107+
108+
stat(join(dir, file), (err, stats) => {
109+
// Ignore files that can't be read
110+
if (err) {
111+
if (--pending === 0) {
112+
return done(results);
92113
}
93114
}
94-
else {
115+
116+
if (stats.isDirectory()) {
117+
if (filter.indexOf(file) === -1) {
118+
walk(join(dir, file), filter, token, (res: string[]) => {
119+
results = results.concat(res);
120+
121+
if (--pending === 0) {
122+
return done(results);
123+
}
124+
});
125+
} else {
126+
if (--pending === 0) {
127+
done(results);
128+
}
129+
}
130+
} else {
95131
if (token.count >= MAX_FILES) {
96132
token.maxReached = true;
97-
return;
98133
}
134+
99135
token.count++;
100-
acceptFile(file);
136+
results.push(file);
137+
138+
if (--pending === 0) {
139+
done(results);
140+
}
101141
}
102-
} catch {
103-
// skip over files for which stat fails
104-
}
142+
});
105143
}
106-
} catch {
107-
// skip over folders that cannot be read
108-
}
109-
};
144+
});
145+
}
110146

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

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

145-
return {
146-
configFiles: asSortedItems(configFiles),
147-
fileTypes: asSortedItems(fileTypes),
148-
fileCount: token.count,
149-
maxFilesReached: token.maxReached
180+
return new Promise((resolve, reject) => {
181+
walk(folder, filter, token, (files) => {
182+
files.forEach(acceptFile);
150183

151-
};
184+
resolve({
185+
configFiles: asSortedItems(configFiles),
186+
fileTypes: asSortedItems(fileTypes),
187+
fileCount: token.count,
188+
maxFilesReached: token.maxReached
189+
190+
});
191+
});
192+
});
152193
}

src/vs/code/electron-main/diagnostics.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export function getPerformanceInfo(info: IMainProcessInfo): Promise<PerformanceI
4949
const workspaceInfoMessages = [];
5050

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

6061
window.folders.forEach(folder => {
61-
try {
62-
const stats = collectWorkspaceStats(folder, ['node_modules', '.git']);
62+
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(async stats => {
63+
6364
let countMessage = `${stats.fileCount} files`;
6465
if (stats.maxFilesReached) {
6566
countMessage = `more than ${countMessage}`;
6667
}
6768
workspaceInfoMessages.push(`| Folder (${basename(folder)}): ${countMessage}`);
6869
workspaceInfoMessages.push(formatWorkspaceStats(stats));
6970

70-
const launchConfigs = collectLaunchConfigs(folder);
71+
const launchConfigs = await collectLaunchConfigs(folder);
7172
if (launchConfigs.length > 0) {
7273
workspaceInfoMessages.push(formatLaunchConfigs(launchConfigs));
7374
}
74-
} catch (error) {
75-
workspaceInfoMessages.push(`| Error: Unable to collect workpsace stats for folder ${folder} (${error.toString()})`);
76-
}
75+
}));
7776
});
7877
});
7978
}
8079

81-
return {
82-
processInfo: formatProcessList(info, rootProcess),
83-
workspaceInfo: workspaceInfoMessages.join('\n')
84-
};
80+
return Promise.all(workspaceStatPromises).then(() => {
81+
return {
82+
processInfo: formatProcessList(info, rootProcess),
83+
workspaceInfo: workspaceInfoMessages.join('\n')
84+
};
85+
}).catch(error => {
86+
return {
87+
processInfo: formatProcessList(info, rootProcess),
88+
workspaceInfo: `Unable to calculate workspace stats: ${error}`
89+
};
90+
});
8591
});
8692
}
8793

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

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

135142
window.folders.forEach(folder => {
136-
try {
137-
const stats = collectWorkspaceStats(folder, ['node_modules', '.git']);
143+
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(async stats => {
138144
let countMessage = `${stats.fileCount} files`;
139145
if (stats.maxFilesReached) {
140146
countMessage = `more than ${countMessage}`;
141147
}
142148
console.log(`| Folder (${basename(folder)}): ${countMessage}`);
143149
console.log(formatWorkspaceStats(stats));
144150

145-
const launchConfigs = collectLaunchConfigs(folder);
146-
if (launchConfigs.length > 0) {
147-
console.log(formatLaunchConfigs(launchConfigs));
148-
}
149-
} catch (error) {
151+
await collectLaunchConfigs(folder).then(launchConfigs => {
152+
if (launchConfigs.length > 0) {
153+
console.log(formatLaunchConfigs(launchConfigs));
154+
}
155+
});
156+
}).catch(error => {
150157
console.log(`| Error: Unable to collect workpsace stats for folder ${folder} (${error.toString()})`);
151-
}
158+
}));
152159
});
153160
});
154161
}
155-
console.log('');
156-
console.log('');
162+
163+
return Promise.all(workspaceStatPromises).then(() => {
164+
console.log('');
165+
console.log('');
166+
});
157167
});
158168
}
159169

0 commit comments

Comments
 (0)