mirror of
https://github.com/github/codeql-action.git
synced 2025-12-27 01:30:10 +08:00
Co-authored-by: Andrew Eisenberg <aeisenberg@github.com> Co-authored-by: Henry Mercer <henrymercer@github.com>
138 lines
4.8 KiB
JavaScript
Executable File
138 lines
4.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
// Automatically installs protoc if not found on $PATH, then
|
|
// runs it transiently.
|
|
|
|
const {spawnSync} = require('child_process');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const {findProtocVersionConfig, listInstalled, findProtocPlugins, findProtobufTs, unzip, makeReleaseName, httpGetRedirect, httpDownload, mkDirRecursive, findProtocInPath, standardInstallDirectory} = require('./util');
|
|
|
|
|
|
main().catch(err => {
|
|
console.error((err instanceof Error) ? err.message : err);
|
|
process.exit(1);
|
|
});
|
|
|
|
|
|
async function main() {
|
|
|
|
// the full path to the protoc executable
|
|
let command;
|
|
// the full path to the include files of a protoc release (well-known-types)
|
|
let includePath;
|
|
|
|
// does the nearest package.json have a config.protocVersion?
|
|
const configuredVersion = findProtocVersionConfig(process.cwd());
|
|
|
|
if (configuredVersion) {
|
|
// we prefer the configured protoc version and install it
|
|
let release = await ensureInstalled(configuredVersion);
|
|
command = release.protocPath;
|
|
includePath = release.includePath;
|
|
} else {
|
|
// there is no configured protoc version. do we have protoc in the $PATH?
|
|
command = findProtocInPath(process.env.PATH)
|
|
if (!command) {
|
|
// no protoc in $PATH, install the latest version
|
|
let release = await ensureInstalled(configuredVersion);
|
|
command = release.protocPath;
|
|
includePath = release.includePath;
|
|
}
|
|
}
|
|
|
|
let args = [
|
|
// pass all arguments to the process
|
|
...process.argv.slice(2),
|
|
];
|
|
|
|
if (includePath) {
|
|
// add the "include" directory of the installed protoc to the proto path
|
|
// do this last, otherwise it can shadow a user input
|
|
args.push("--proto_path", includePath);
|
|
}
|
|
|
|
// search for @protobuf-ts/plugin in node_modules and add --proto_path argument
|
|
let protobufTs = findProtobufTs(process.cwd());
|
|
if (protobufTs) {
|
|
args.push("--proto_path", protobufTs);
|
|
}
|
|
|
|
// search for any protoc-gen-xxx plugins in .bin and add --plugin arguments for them
|
|
for (let plugin of findProtocPlugins(process.cwd())) {
|
|
args.unshift("--plugin", plugin);
|
|
}
|
|
|
|
let child = spawnSync(command, args, {
|
|
// protoc accepts stdin for some commands, pipe all IO
|
|
stdio: [process.stdin, process.stdout, process.stderr],
|
|
shell: false
|
|
});
|
|
|
|
if (child.error) {
|
|
throw new Error("@protobuf-ts/protoc was unable to spawn protoc. " + child.error);
|
|
}
|
|
process.exit(child.status);
|
|
}
|
|
|
|
|
|
async function ensureInstalled(version) {
|
|
// resolve the latest release version number if necessary
|
|
if (version === "latest" || version === undefined) {
|
|
let latestLocation;
|
|
try {
|
|
latestLocation = await httpGetRedirect("https://github.com/protocolbuffers/protobuf/releases/latest");
|
|
} catch (e) {
|
|
throw new Error(`@protobuf-ts/protoc failed to retrieve latest protoc version number: ${e}`);
|
|
}
|
|
version = latestLocation.split("/v").pop();
|
|
}
|
|
|
|
// make the release name for the current platform and the requested version number
|
|
let releaseName = makeReleaseName({
|
|
platform: os.platform(),
|
|
arch: os.arch(),
|
|
version: version
|
|
});
|
|
|
|
// if this release is already installed, we are done here
|
|
let alreadyInstalled = listInstalled().find(i => i.name === releaseName);
|
|
if (alreadyInstalled) {
|
|
return alreadyInstalled;
|
|
}
|
|
|
|
// download the release
|
|
let archive;
|
|
try {
|
|
archive = await httpDownload(`https://github.com/protocolbuffers/protobuf/releases/download/v${version}/${releaseName}.zip`);
|
|
} catch (e) {
|
|
throw new Error(`@protobuf-ts/protoc failed to download protoc v${version}. \nDid you misspell the version number? The version number must look like "3.0.12", without a leading "v".\n${e}`);
|
|
}
|
|
|
|
// unzip the archive
|
|
let archivePath = path.join(standardInstallDirectory, releaseName);
|
|
try {
|
|
unzip(archive, (data, header) => {
|
|
let filename = path.join(archivePath, header.filename);
|
|
mkDirRecursive(path.dirname(filename));
|
|
fs.writeFileSync(filename, data, {
|
|
mode: header.filename.includes("bin/") ? 0o755 : 0o666
|
|
});
|
|
});
|
|
} catch (e) {
|
|
throw new Error(`@protobuf-ts/protoc failed unzip the downloaded protoc release v${version}: ${e}`);
|
|
}
|
|
|
|
// sanity check
|
|
let installed = listInstalled().find(i => i.name === releaseName);
|
|
if (!installed) {
|
|
throw new Error(`@protobuf-ts/protoc failed to install protoc v${version}.`);
|
|
}
|
|
|
|
// finished
|
|
console.info(`@protobuf-ts/protoc installed protoc v${installed.version}.`);
|
|
return installed;
|
|
}
|
|
|