/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as os from 'os'; import { virtualMachineHint } from 'vs/base/node/id'; import { IMachineInfo, WorkspaceStats, WorkspaceStatItem } from 'vs/platform/diagnostics/common/diagnosticsService'; import { readdir, stat } from 'fs'; import { join } from 'vs/base/common/path'; export function getMachineInfo(): IMachineInfo { const MB = 1024 * 1024; const GB = 1024 * MB; const machineInfo: IMachineInfo = { os: `${os.type()} ${os.arch()} ${os.release()}`, memory: `${(os.totalmem() / GB).toFixed(2)}GB (${(os.freemem() / GB).toFixed(2)}GB free)`, vmHint: `${Math.round((virtualMachineHint.value() * 100))}%`, }; const cpus = os.cpus(); if (cpus && cpus.length > 0) { machineInfo.cpus = `${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`; } return machineInfo; } export function collectWorkspaceStats(folder: string, filter: string[]): Promise { const configFilePatterns = [ { 'tag': 'grunt.js', 'pattern': /^gruntfile\.js$/i }, { 'tag': 'gulp.js', 'pattern': /^gulpfile\.js$/i }, { 'tag': 'tsconfig.json', 'pattern': /^tsconfig\.json$/i }, { 'tag': 'package.json', 'pattern': /^package\.json$/i }, { 'tag': 'jsconfig.json', 'pattern': /^jsconfig\.json$/i }, { 'tag': 'tslint.json', 'pattern': /^tslint\.json$/i }, { 'tag': 'eslint.json', 'pattern': /^eslint\.json$/i }, { 'tag': 'tasks.json', 'pattern': /^tasks\.json$/i }, { 'tag': 'launch.json', 'pattern': /^launch\.json$/i }, { 'tag': 'settings.json', 'pattern': /^settings\.json$/i }, { 'tag': 'webpack.config.js', 'pattern': /^webpack\.config\.js$/i }, { 'tag': 'project.json', 'pattern': /^project\.json$/i }, { 'tag': 'makefile', 'pattern': /^makefile$/i }, { 'tag': 'sln', 'pattern': /^.+\.sln$/i }, { 'tag': 'csproj', 'pattern': /^.+\.csproj$/i }, { 'tag': 'cmake', 'pattern': /^.+\.cmake$/i } ]; const fileTypes = new Map(); const configFiles = new Map(); const MAX_FILES = 20000; function walk(dir: string, filter: string[], token: { count: number, maxReached: boolean }, done: (allFiles: string[]) => void): void { let results: string[] = []; 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 done(results); } 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; } token.count++; results.push(file); if (--pending === 0) { done(results); } } } }); } }); } const addFileType = (fileType: string) => { if (fileTypes.has(fileType)) { fileTypes.set(fileType, fileTypes.get(fileType)! + 1); } else { fileTypes.set(fileType, 1); } }; const addConfigFiles = (fileName: string) => { for (const each of configFilePatterns) { if (each.pattern.test(fileName)) { if (configFiles.has(each.tag)) { configFiles.set(each.tag, configFiles.get(each.tag)! + 1); } else { configFiles.set(each.tag, 1); } } } }; const acceptFile = (name: string) => { if (name.lastIndexOf('.') >= 0) { const suffix: string | undefined = name.split('.').pop(); if (suffix) { addFileType(suffix); } } addConfigFiles(name); }; const token: { count: number, maxReached: boolean } = { count: 0, maxReached: false }; return new Promise((resolve, reject) => { walk(folder, filter, token, async (files) => { files.forEach(acceptFile); // TODO@rachel commented out due to severe performance issues // see https://github.com/Microsoft/vscode/issues/70563 // const launchConfigs = await collectLaunchConfigs(folder); resolve({ configFiles: asSortedItems(configFiles), fileTypes: asSortedItems(fileTypes), fileCount: token.count, maxFilesReached: token.maxReached, // launchConfigFiles: launchConfigs }); }); }); } function asSortedItems(map: Map): WorkspaceStatItem[] { const a: WorkspaceStatItem[] = []; map.forEach((value, index) => a.push({ name: index, count: value })); return a.sort((a, b) => b.count - a.count); }