Initial commit

This commit is contained in:
jiapengyu
2026-07-27 13:37:48 +08:00
commit ecba71e2a5
39123 changed files with 5989154 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
## /utils
Contains utilities for NodeGit
#### buildFlags
Determines how NodeGit should build. Use `BUILD_ONLY` environment variable to build from source.
## discoverOpenSSLDistros
Crawls a series of static URLS on the [Conan package manager](https://conan.io/) for the [latest release of OpenSSL](https://bintray.com/conan-community/conan/OpenSSL%3Aconan#files/conan%2FOpenSSL%2F1.1.0i) (1.1.0i at the time of writing). It acquires URLS for releases of statically linked binaries and header files of OpenSSL for Mac and Windows. The provided binaries are compiled on:
* Mac: clang-8.1 or clang-9.
* Windows: vs12, vs14, vs15
The discovered distributions are written into `vendor/static_config/openssl_distributions.json`. This script does not need to be run unless you are updating the version of OpenSSL to build against.
## acquireOpenSSL
Download the OpenSSL binaries and headers applicable to the current OS for the latest compiler version (clang-9/vs14). Uses links from `vendor/static_config/openssl_distributions.json`.
TODO:
* Make the script pull the debug versions if node-gyp is building in debug mode
* Make the script pull down a version of the binaries that matches the system compiler
+87
View File
@@ -0,0 +1,87 @@
const fse = require("fs-extra");
const path = require("path");
const R = require("ramda");
const got = require("got");
const stream = require("stream");
const tar = require("tar-fs");
const zlib = require("zlib");
const vendorPath = path.resolve(__dirname, "..", "vendor");
const distrosFilePath = path.join(vendorPath, "static_config", "openssl_distributions.json");
const extractPath = path.join(vendorPath, "openssl");
const getOSName = () => {
if (process.platform === "win32") {
if (process.arch === "x64") {
return "win64";
} else {
return "win32";
}
} else if (process.platform === "darwin") {
return "macOS";
} else {
// We only discover distros for Mac and Windows. We don't care about any other OS.
return "unknown";
}
};
const getCompilerVersion = () => {
// TODO: Get actual compiler version. For now, just assume latest compiler for distros in openssl_distributions.js
const osName = getOSName();
if (osName === "win32" || osName === "win64") {
return "vs14";
} else if (osName === "macOS") {
return "clang-9";
} else {
// We only discover distros for Mac and Windows. We don't care about any other OS.
return "unknown";
}
};
// TODO: Determine if we are GYPing in Debug
const getIsDebug = () => false;
const getMatchingDistributionName = () =>
`${getOSName()}-${getCompilerVersion()}-static${getIsDebug() ? "-debug" : "-release"}`;
const getDistributionsConfig = () =>
fse.readFile(distrosFilePath, "utf8")
.then(JSON.parse);
const getDistrbutionURLFromConfig = (config) => {
const distName = getMatchingDistributionName();
const distURL = R.propOr(null, distName, config);
if (!distURL) {
return Promise.reject(new Error("No matching distribution for this operating system"));
}
return Promise.resolve(distURL);
};
const fetchFileFromURL = (distUrl) => got(distUrl, {
responseType: 'buffer'
}).then(({ body }) => body);
const extractFile = (body) => new Promise((resolve, reject) => {
const streamableBody = new stream.Readable();
streamableBody.push(body);
streamableBody.push(null);
streamableBody
.pipe(zlib.createGunzip())
.on("error", reject)
.pipe(tar.extract(extractPath))
.on("error", reject)
.on("close", resolve);
});
const acquireOpenSSL = () =>
getDistributionsConfig()
.then(getDistrbutionURLFromConfig)
.then(fetchFileFromURL)
.then(extractFile)
.catch((e) => {
console.error(e);
process.exit(1);
});
acquireOpenSSL();
+19
View File
@@ -0,0 +1,19 @@
var fs = require("fs");
var path = require("path");
var isGitRepo;
try {
fs.statSync(path.join(__dirname, "..", ".git"));
isGitRepo = true;
} catch (e) {
isGitRepo = false;
}
module.exports = {
debugBuild: !!process.env.BUILD_DEBUG,
isElectron: process.env.npm_config_runtime === "electron",
isGitRepo: isGitRepo,
isNwjs: process.env.npm_config_runtime === "node-webkit",
mustBuild: !!(isGitRepo || process.env.BUILD_DEBUG || process.env.BUILD_ONLY)
};
+50
View File
@@ -0,0 +1,50 @@
var cp = require("child_process");
var fse = require("fs-extra");
var path = require("path");
const libssh2VendorDirectory = path.resolve(__dirname, "..", "vendor", "libssh2");
const libssh2ConfigureScript = path.join(libssh2VendorDirectory, "configure");
const libssh2StaticConfigDirectory = path.resolve(__dirname, "..", "vendor", "static_config", "libssh2");
module.exports = function retrieveExternalDependencies() {
console.info("[nodegit] Configuring libssh2.");
// Copy Windows / Mac preconfigured files
if (process.platform === "win32" || process.platform === "darwin") {
return fse.copy(
path.join(libssh2StaticConfigDirectory, process.platform),
path.join(libssh2VendorDirectory, "src")
);
}
// Run the `configure` script on Linux
return new Promise(function(resolve, reject) {
var newEnv = {};
Object.keys(process.env).forEach(function(key) {
newEnv[key] = process.env[key];
});
cp.exec(
libssh2ConfigureScript,
{
cwd: libssh2VendorDirectory,
env: newEnv
},
function(err, stdout, stderr) {
if (err) {
console.error(err);
console.error(stderr);
reject(err, stderr);
}
else {
resolve(stdout);
}
}
);
});
};
// Called on the command line
if (require.main === module) {
module.exports();
}
+184
View File
@@ -0,0 +1,184 @@
const cheerio = require("cheerio");
const fse = require("fs-extra");
const path = require("path");
const R = require("ramda");
const got = require("got");
const windowsCommonConditions = [
R.test(/^\s*os=Windows$/gm),
R.test(/^\s*shared=False$/gm)
];
const macCommonConditions = [
R.test(/^\s*arch=x86_64$/gm),
R.test(/^\s*os=Macos$/gm),
R.test(/^\s*compiler=apple-clang$/gm),
R.test(/^\s*shared=False$/gm)
];
const debugPairs = R.toPairs({
"win32-vs12-static-debug": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86$/gm),
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.runtime=MTd$/gm),
R.test(/^\s*compiler\.version=12$/gm)
]),
"win32-vs14-static-debug": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86$/gm),
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.runtime=MTd$/gm),
R.test(/^\s*compiler\.version=14$/gm)
]),
"win32-vs15-static-debug": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86$/gm),
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.runtime=MTd$/gm),
R.test(/^\s*compiler\.version=15$/gm)
]),
"win64-vs12-static-debug": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86_64$/gm),
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.runtime=MTd$/gm),
R.test(/^\s*compiler\.version=12$/gm)
]),
"win64-vs14-static-debug": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86_64$/gm),
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.runtime=MTd$/gm),
R.test(/^\s*compiler\.version=14$/gm)
]),
"win64-vs15-static-debug": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86_64$/gm),
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.runtime=MTd$/gm),
R.test(/^\s*compiler\.version=15$/gm)
]),
"macOS-clang-9-static-debug": R.allPass([
...macCommonConditions,
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.version=9.0$/gm)
]),
"macOS-clang-8.1-static-debug": R.allPass([
...macCommonConditions,
R.test(/^\s*build_type=Debug$/gm),
R.test(/^\s*compiler\.version=8\.1$/gm)
])
});
const releasePairs = R.toPairs({
"win32-vs12-static-release": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86$/gm),
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.runtime=MT$/gm),
R.test(/^\s*compiler\.version=12$/gm)
]),
"win32-vs14-static-release": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86$/gm),
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.runtime=MT$/gm),
R.test(/^\s*compiler\.version=14$/gm)
]),
"win32-vs15-static-release": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86$/gm),
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.runtime=MT$/gm),
R.test(/^\s*compiler\.version=15$/gm)
]),
"win64-vs12-static-release": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86_64$/gm),
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.runtime=MT$/gm),
R.test(/^\s*compiler\.version=12$/gm)
]),
"win64-vs14-static-release": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86_64$/gm),
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.runtime=MT$/gm),
R.test(/^\s*compiler\.version=14$/gm)
]),
"win64-vs15-static-release": R.allPass([
...windowsCommonConditions,
R.test(/^\s*arch=x86_64$/gm),
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.runtime=MT$/gm),
R.test(/^\s*compiler\.version=15$/gm)
]),
"macOS-clang-9-static-release": R.allPass([
...macCommonConditions,
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.version=9.0$/gm)
]),
"macOS-clang-8.1-static-release": R.allPass([
...macCommonConditions,
R.test(/^\s*build_type=Release$/gm),
R.test(/^\s*compiler\.version=8\.1$/gm)
])
});
const distributionPairs = [...debugPairs, ...releasePairs];
const getDistributionConfigURLFromHash = itemHash =>
`https://dl.bintray.com/conan-community/conan/conan/OpenSSL/1.1.1c/stable/0/package/${itemHash}/0/conaninfo.txt`;
const getDistributionDownloadURLFromHash = itemHash =>
`https://dl.bintray.com/conan-community/conan/conan/OpenSSL/1.1.1c/stable/0/package/${itemHash}/0/conan_package.tgz`;
const getDistributionsRootURL = () =>
"https://dl.bintray.com/conan-community/conan/conan/OpenSSL/1.1.1c/stable/0/package/";
const detectDistributionPairFromConfig = (itemHash, body) => R.pipe(
R.find(([_, predicate]) => predicate(body)),
(distributionPair) => distributionPair
? [distributionPair[0], getDistributionDownloadURLFromHash(itemHash)]
: undefined
)(distributionPairs);
const getDistributionConfig = (itemHash) =>
got(getDistributionConfigURLFromHash(itemHash))
.then(({ body }) => detectDistributionPairFromConfig(itemHash, body));
const discoverDistributions = (treeHtml) => {
const releaseHashes = [];
const $ = cheerio.load(treeHtml);
$("a").each((_, link) => {
const linkText = link.children[0].data;
if (!linkText) {
return;
}
// Trim off the trailing '/'
const releaseHash = linkText.substring(0, linkText.length - 1);
releaseHashes.push(releaseHash);
});
return Promise.all(
R.map(releaseHash => getDistributionConfig(releaseHash), releaseHashes)
);
}
const writeFile = (distributions) =>
fse.ensureDir(path.dirname(outputPath))
.then(fse.writeFile(outputPath, JSON.stringify(distributions, null, 2)));
const outputPath = path.resolve(__dirname, "..", "vendor", "static_config", "openssl_distributions.json");
got(getDistributionsRootURL())
.then(({ body }) => discoverDistributions(body))
.then(R.filter(R.identity))
.then(R.sortBy(R.prop(0)))
.then(R.fromPairs)
.then(writeFile);
+17
View File
@@ -0,0 +1,17 @@
var cp = require('child_process');
// We have to manually promisify this because at this is required in lifecycle
// methods and we are not guaranteed that any 3rd party packages are installed
// at this point
module.exports = function(command, opts) {
return new Promise(function(resolve, reject) {
return cp.exec(command, opts, function(err, result) {
if (err) {
reject(err);
}
else {
resolve(result);
}
});
});
};
+23
View File
@@ -0,0 +1,23 @@
var cp = require("child_process");
module.exports = function gitExecutableLocation() {
return new Promise(function(resolve, reject) {
var cmd;
if (process.platform === "win32") {
cmd = "where git";
}
else {
cmd = "which git";
}
cp.exec(cmd, function(err, stdout, stderr) {
if (err) {
reject(err, stderr);
}
else {
resolve(stdout);
}
});
});
};
+30
View File
@@ -0,0 +1,30 @@
const fs = require("fs")
const JSON5 = require("json5");
const path = require("path");
if (process.argv.length < 3) {
process.exit(1);
}
const last = arr => arr[arr.length - 1];
const [, , nodeRootDir] = process.argv;
let isElectron = last(nodeRootDir.split(path.sep)).startsWith("iojs");
if (!isElectron) {
try {
// Not ideal, would love it if there were a full featured gyp package to do this operation instead.
const { variables: { built_with_electron } } = JSON5.parse(
fs.readFileSync(
path.resolve(nodeRootDir, "include", "node", "config.gypi"),
"utf8"
)
);
if (built_with_electron) {
isElectron = true;
}
} catch (e) {}
}
process.stdout.write(isElectron ? "1" : "0");
+51
View File
@@ -0,0 +1,51 @@
const { spawn } = require('child_process');
const [, , cmd, ...args] = process.argv;
if (!cmd) {
process.exit(-1);
}
const once = (fn) => {
let runOnce = false;
return (...args) => {
if (runOnce) {
return;
}
runOnce = true;
fn(...args);
}
};
const retry = (numRetries = 3) => {
const child = spawn(cmd, args, {
shell: process.platform === 'win32',
stdio: [0, 'pipe', 'pipe']
});
child.setMaxListeners(0);
child.stdout.setEncoding('utf8');
child.stderr.setEncoding('utf8');
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
const cleanupAndExit = once((error, status) => {
child.kill();
if (numRetries > 0 && (error || status !== 0)) {
retry(numRetries - 1);
} else if (error) {
console.log(error);
process.exit(-1);
} else {
process.exit(status);
}
});
const onClose = status => cleanupAndExit(null, status);
child.on('close', onClose);
child.on('error', cleanupAndExit);
};
retry();