Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: cache results in runtime-info #12320

Merged
merged 1 commit into from Sep 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
179 changes: 95 additions & 84 deletions lib/shared/runtime-info.js
Expand Up @@ -20,110 +20,121 @@ const packageJson = require("../../package.json");
//------------------------------------------------------------------------------

/**
* Checks if a path is a child of a directory.
* @param {string} parentPath - The parent path to check.
* @param {string} childPath - The path to check.
* @returns {boolean} Whether or not the given path is a child of a directory.
*/
function isChildOfDirectory(parentPath, childPath) {
return !path.relative(parentPath, childPath).startsWith("..");
}

/**
* Synchronously executes a shell command and formats the result.
* @param {string} cmd - The command to execute.
* @param {Array} args - The arguments to be executed with the command.
* @returns {string} The version returned by the command.
* Generates and returns execution environment information.
* @returns {string} A string that contains execution environment information.
*/
function execCommand(cmd, args) {
const process = spawn.sync(cmd, args, { encoding: "utf8" });

if (process.error) {
throw process.error;
function environment() {
const cache = new Map();

/**
* Checks if a path is a child of a directory.
* @param {string} parentPath - The parent path to check.
* @param {string} childPath - The path to check.
* @returns {boolean} Whether or not the given path is a child of a directory.
*/
function isChildOfDirectory(parentPath, childPath) {
return !path.relative(parentPath, childPath).startsWith("..");
}

return process.stdout.trim();
}
/**
* Synchronously executes a shell command and formats the result.
* @param {string} cmd - The command to execute.
* @param {Array} args - The arguments to be executed with the command.
* @returns {string} The version returned by the command.
*/
function execCommand(cmd, args) {
const key = [cmd, ...args].join(" ");

if (cache.has(key)) {
return cache.get(key);
}

/**
* Normalizes a version number.
* @param {string} versionStr - The string to normalize.
* @returns {string} The normalized version number.
*/
function normalizeVersionStr(versionStr) {
return versionStr.startsWith("v") ? versionStr : `v${versionStr}`;
}
const process = spawn.sync(cmd, args, { encoding: "utf8" });

/**
* Gets bin version.
* @param {string} bin - The bin to check.
* @returns {string} The normalized version returned by the command.
*/
function getBinVersion(bin) {
const binArgs = ["--version"];

try {
return normalizeVersionStr(execCommand(bin, binArgs));
} catch (e) {
log.error(`Error finding ${bin} version running the command \`${bin} ${binArgs.join(" ")}\``);
throw e;
}
}
if (process.error) {
throw process.error;
}

/**
* Gets installed npm package version.
* @param {string} pkg - The package to check.
* @param {boolean} global - Whether to check globally or not.
* @returns {string} The normalized version returned by the command.
*/
function getNpmPackageVersion(pkg, { global = false } = {}) {
const npmBinArgs = ["bin", "-g"];
const npmLsArgs = ["ls", "--depth=0", "--json", "eslint"];
const result = process.stdout.trim();

if (global) {
npmLsArgs.push("-g");
cache.set(key, result);
return result;
}

try {
const parsedStdout = JSON.parse(execCommand("npm", npmLsArgs));

/*
* Checking globally returns an empty JSON object, while local checks
* include the name and version of the local project.
*/
if (isEmpty(parsedStdout) || !(parsedStdout.dependencies && parsedStdout.dependencies.eslint)) {
return "Not found";
}
/**
* Normalizes a version number.
* @param {string} versionStr - The string to normalize.
* @returns {string} The normalized version number.
*/
function normalizeVersionStr(versionStr) {
return versionStr.startsWith("v") ? versionStr : `v${versionStr}`;
}

const [, processBinPath] = process.argv;
let npmBinPath;
/**
* Gets bin version.
* @param {string} bin - The bin to check.
* @returns {string} The normalized version returned by the command.
*/
function getBinVersion(bin) {
const binArgs = ["--version"];

try {
npmBinPath = execCommand("npm", npmBinArgs);
return normalizeVersionStr(execCommand(bin, binArgs));
} catch (e) {
log.error(`Error finding npm binary path when running command \`npm ${npmBinArgs.join(" ")}\``);
log.error(`Error finding ${bin} version running the command \`${bin} ${binArgs.join(" ")}\``);
throw e;
}
}

const isGlobal = isChildOfDirectory(npmBinPath, processBinPath);
let pkgVersion = parsedStdout.dependencies.eslint.version;

if ((global && isGlobal) || (!global && !isGlobal)) {
pkgVersion += " (Currently used)";
/**
* Gets installed npm package version.
* @param {string} pkg - The package to check.
* @param {boolean} global - Whether to check globally or not.
* @returns {string} The normalized version returned by the command.
*/
function getNpmPackageVersion(pkg, { global = false } = {}) {
const npmBinArgs = ["bin", "-g"];
const npmLsArgs = ["ls", "--depth=0", "--json", "eslint"];

if (global) {
npmLsArgs.push("-g");
}

return normalizeVersionStr(pkgVersion);
} catch (e) {
log.error(`Error finding ${pkg} version running the command \`npm ${npmLsArgs.join(" ")}\``);
throw e;
try {
const parsedStdout = JSON.parse(execCommand("npm", npmLsArgs));

/*
* Checking globally returns an empty JSON object, while local checks
* include the name and version of the local project.
*/
if (isEmpty(parsedStdout) || !(parsedStdout.dependencies && parsedStdout.dependencies.eslint)) {
return "Not found";
}

const [, processBinPath] = process.argv;
let npmBinPath;

try {
npmBinPath = execCommand("npm", npmBinArgs);
} catch (e) {
log.error(`Error finding npm binary path when running command \`npm ${npmBinArgs.join(" ")}\``);
throw e;
}

const isGlobal = isChildOfDirectory(npmBinPath, processBinPath);
let pkgVersion = parsedStdout.dependencies.eslint.version;

if ((global && isGlobal) || (!global && !isGlobal)) {
pkgVersion += " (Currently used)";
}

return normalizeVersionStr(pkgVersion);
} catch (e) {
log.error(`Error finding ${pkg} version running the command \`npm ${npmLsArgs.join(" ")}\``);
throw e;
}
}
}

/**
* Generates and returns execution environment information.
* @returns {string} A string that contains execution environment information.
*/
function environment() {
return [
"Environment Info:",
"",
Expand Down
4 changes: 2 additions & 2 deletions tests/lib/shared/runtime-info.js
Expand Up @@ -86,8 +86,7 @@ describe("RuntimeInfo", () => {
}
}
}
`,
NPM_BIN_PATH
`
];
});

Expand Down Expand Up @@ -138,6 +137,7 @@ describe("RuntimeInfo", () => {
"version": "1.0.0"
}
`);
spawnSyncStubArgs.push(NPM_BIN_PATH);
setupSpawnSyncStubReturnVals(spawnSyncStub, spawnSyncStubArgs);
process.argv[1] = GLOBAL_ESLINT_BIN_PATH;

Expand Down