diff --git a/CHANGELOG.md b/CHANGELOG.md
index 12d3a9dce..57d0616de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Change Log
+## v0.28.0-alpha.35 [(2025-06-03)](https://github.com/nodegit/nodegit/releases/tag/v0.28.0-alpha.35)
+
+[Full Changelog](https://github.com/nodegit/nodegit/compare/v0.28.0-alpha.34...v0.28.0-alpha.35)
+
+#### Summary of Changes
+ - Bump libgit2 to 1.9.1
+ - Bump OpenSSL to 3.0
+ - Move OpenSSL Packaging to Github Actions
+ - Add arm64 build Support
+
+#### Merged PRs into NodeGit
+- [Bump libgit2 to 1.9.1](https://github.com/nodegit/nodegit/pull/2025)
+- [Bump OpenSSL to 3.0, Move OpenSSL package generation to Github Actions](https://github.com/nodegit/nodegit/pull/2026)
+- [fix: correct macos arch labels](github.com/nodegit/nodegit/pull/2027)
+- [Add Ability to compile for arm64](https://github.com/nodegit/nodegit/pull/2028)
+
## v0.28.0-alpha.34 [(2025-06-03)](https://github.com/nodegit/nodegit/releases/tag/v0.28.0-alpha.34)
[Full Changelog](https://github.com/nodegit/nodegit/compare/v0.28.0-alpha.33...v0.28.0-alpha.34)
diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json
index 889b792e7..99837534d 100644
--- a/generate/input/descriptor.json
+++ b/generate/input/descriptor.json
@@ -1526,6 +1526,11 @@
}
}
},
+ "email": {
+ "cDependencies": [
+ "git2/sys/email.h"
+ ]
+ },
"email_create_options": {
"hasConstructor": true
},
diff --git a/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json
index 09433e7fa..742216f03 100644
--- a/generate/input/libgit2-supplement.json
+++ b/generate/input/libgit2-supplement.json
@@ -294,6 +294,54 @@
"isErrorCode": true
}
},
+ "git_email_create_from_diff": {
+ "file": "sys/email.h",
+ "type": "function",
+ "isAsync": true,
+ "group": "email",
+ "args": [
+ {
+ "name": "out",
+ "type": "git_buf *"
+ },
+ {
+ "name": "diff",
+ "type": "git_diff *"
+ },
+ {
+ "name": "patch_idx",
+ "type": "size_t"
+ },
+ {
+ "name": "patch_count",
+ "type": "size_t"
+ },
+ {
+ "name": "commit_id",
+ "type": "const git_oid *"
+ },
+ {
+ "name": "summary",
+ "type": "const char *"
+ },
+ {
+ "name": "body",
+ "type": "const char *"
+ },
+ {
+ "name": "author",
+ "type": "const git_signature *"
+ },
+ {
+ "name": "opts",
+ "type": "git_email_create_options *"
+ }
+ ],
+ "return": {
+ "type": "int",
+ "isErrorCode": true
+ }
+ },
"git_diff_get_perfdata": {
"file": "sys/diff.h",
"args": [
@@ -2619,6 +2667,9 @@
"blame": [
"git_blame_file"
],
+ "email": [
+ "git_email_create_from_diff"
+ ],
"note": [
"git_note_author",
"git_note_commit_create",
diff --git a/generate/templates/templates/binding.gyp b/generate/templates/templates/binding.gyp
index 61cad0cb5..b5e189c32 100644
--- a/generate/templates/templates/binding.gyp
+++ b/generate/templates/templates/binding.gyp
@@ -160,9 +160,8 @@
"<(electron_openssl_root)/include"
],
"libraries": [
- # this order is significant on centos7 apparently...
- "<(electron_openssl_root)/lib/libssl.a",
- "<(electron_openssl_root)/lib/libcrypto.a"
+ "<(electron_openssl_root)/lib64/libssl.a",
+ "<(electron_openssl_root)/lib64/libcrypto.a"
]
}],
["<(is_electron) == 1 and <(electron_openssl_static) != 1", {
diff --git a/utils/acquireOpenSSL.mjs b/utils/acquireOpenSSL.mjs
index 1d83f540b..044454026 100644
--- a/utils/acquireOpenSSL.mjs
+++ b/utils/acquireOpenSSL.mjs
@@ -1,4 +1,5 @@
import crypto from "crypto";
+import { spawn } from "child_process";
import execPromise from "./execPromise.js";
import got from "got";
import path from "path";
@@ -7,19 +8,40 @@ import tar from "tar-fs";
import zlib from "zlib";
import { createWriteStream, promises as fs } from "fs";
import { performance } from "perf_hooks";
-import { fileURLToPath } from 'url';
import { promisify } from "util";
const pipeline = promisify(stream.pipeline);
import packageJson from '../package.json' with { type: "json" };
-const OPENSSL_VERSION = "1.1.1t";
+const OPENSSL_VERSION = "3.0.18";
const win32BatPath = path.join(import.meta.dirname, "build-openssl.bat");
const vendorPath = path.resolve(import.meta.dirname, "..", "vendor");
const opensslPatchPath = path.join(vendorPath, "patches", "openssl");
const extractPath = path.join(vendorPath, "openssl");
+const exists = (filePath) => fs.stat(filePath).then(() => true).catch(() => false);
+
+const convertArch = (archStr) => {
+ const convertedArch = {
+ 'ia32': 'x86',
+ 'x86': 'x86',
+ 'x64': 'x64',
+ 'arm64': 'arm64'
+ }[archStr];
+
+ if (!convertedArch) {
+ throw new Error('unsupported architecture');
+ }
+
+ return convertedArch;
+}
+
+const hostArch = convertArch(process.arch);
+const targetArch = process.env.npm_config_arch
+ ? convertArch(process.env.npm_config_arch)
+ : hostArch;
+
const pathsToIncludeForPackage = [
"include", "lib"
];
@@ -56,6 +78,8 @@ const makeHashVerifyOnFinal = (expected) => (digest) => {
// currently this only needs to be done on linux
const applyOpenSSLPatches = async (buildCwd, operatingSystem) => {
try {
+ await fs.access(opensslPatchPath);
+
for (const patchFilename of await fs.readdir(opensslPatchPath)) {
const patchTarget = patchFilename.split("-")[1];
if (patchFilename.split(".").pop() === "patch" && (patchTarget === operatingSystem || patchTarget === "all")) {
@@ -66,6 +90,11 @@ const applyOpenSSLPatches = async (buildCwd, operatingSystem) => {
}
}
} catch(e) {
+ if (e.code === "ENOENT") {
+ // no patches to apply
+ return;
+ }
+
console.log("Patch application failed: ", e);
throw e;
}
@@ -76,8 +105,10 @@ const buildDarwin = async (buildCwd, macOsDeploymentTarget) => {
throw new Error("Expected macOsDeploymentTarget to be specified");
}
+ const buildConfig = targetArch === "x64" ? "darwin64-x86_64-cc" : "darwin64-arm64-cc";
+
const configureArgs = [
- process.arch === "x64" ? "darwin64-x86_64-cc" : "darwin64-arm64-cc",
+ buildConfig,
// speed up ecdh on little-endian platforms with 128bit int support
"enable-ec_nistp_64_gcc_128",
// compile static libraries
@@ -86,6 +117,8 @@ const buildDarwin = async (buildCwd, macOsDeploymentTarget) => {
"no-ssl2",
"no-ssl3",
"no-comp",
+ // disable tty ui since it fails a bunch of tests on GHA runners and we're just gonna link anyways
+ "no-ui-console",
// set install directory
`--prefix="${extractPath}"`,
`--openssldir="${extractPath}"`,
@@ -99,7 +132,7 @@ const buildDarwin = async (buildCwd, macOsDeploymentTarget) => {
await applyOpenSSLPatches(buildCwd, "darwin");
- // only build the libraries, not the tests/fuzzer or apps
+ // only build the libraries, not the fuzzer or apps
await execPromise("make build_libs", {
cwd: buildCwd
}, { pipeOutput: true });
@@ -115,13 +148,15 @@ const buildDarwin = async (buildCwd, macOsDeploymentTarget) => {
};
const buildLinux = async (buildCwd) => {
+ const buildConfig = targetArch === "x64" ? "linux-x86_64" : "linux-aarch64";
+
const configureArgs = [
- "linux-x86_64",
+ buildConfig,
// Electron(at least on centos7) imports the libcups library at runtime, which has a
// dependency on the system libssl/libcrypto which causes symbol conflicts and segfaults.
// To fix this we need to hide all the openssl symbols to prevent them from being overridden
// by the runtime linker.
- "-fvisibility=hidden",
+ // "-fvisibility=hidden",
// compile static libraries
"no-shared",
// disable ssl2, ssl3, and compression
@@ -138,7 +173,7 @@ const buildLinux = async (buildCwd) => {
await applyOpenSSLPatches(buildCwd, "linux");
- // only build the libraries, not the tests/fuzzer or apps
+ // only build the libraries, not the fuzzer or apps
await execPromise("make build_libs", {
cwd: buildCwd
}, { pipeOutput: true });
@@ -154,44 +189,108 @@ const buildLinux = async (buildCwd) => {
}, { pipeOutput: true });
};
-const buildWin32 = async (buildCwd, vsBuildArch) => {
- if (!vsBuildArch) {
- throw new Error("Expected vsBuildArch to be specified");
- }
+const buildWin32 = async (buildCwd) => {
+ let vcvarsallPath = undefined;
- const programFilesPath = (process.arch === "x64"
- ? process.env["ProgramFiles(x86)"]
- : process.env.ProgramFiles) || "C:\\Program Files";
- const vcvarsallPath = process.env.npm_config_vcvarsall_path || `${
- programFilesPath
- }\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\Auxiliary\\Build\\vcvarsall.bat`;
- try {
- await fs.stat(vcvarsallPath);
- } catch {
- throw new Error(`vcvarsall.bat not found at ${vcvarsallPath}`);
+ if (process.env.npm_config_vcvarsall_path && await exists(process.env.npm_config_vcvarsall_path)) {
+ vcvarsallPath = process.env.npm_config_vcvarsall_path;
+ } else {
+ const potentialMsvsPaths = [];
+
+ // GYP_MSVS_OVERRIDE_PATH is set by node-gyp so this should cover most cases
+ if (process.env.GYP_MSVS_OVERRIDE_PATH) {
+ potentialMsvsPaths.push(process.env.GYP_MSVS_OVERRIDE_PATH);
+ }
+
+ const packageTypes = ["BuildTools", "Community", "Professional", "Enterprise"];
+ const versions = ["2022", "2019"]
+
+ const computePossiblePaths = (parentPath) => {
+ let possiblePaths = []
+ for (const packageType of packageTypes) {
+ for (const version of versions) {
+ possiblePaths.push(path.join(parentPath, version, packageType));
+ }
+ }
+
+ return possiblePaths;
+ }
+
+ if (process.env["ProgramFiles(x86)"]) {
+ const parentPath = path.join(process.env["ProgramFiles(x86)"], 'Microsoft Visual Studio');
+ potentialMsvsPaths.push(...computePossiblePaths(parentPath));
+ }
+
+ if (process.env.ProgramFiles) {
+ const parentPath = path.join(process.env.ProgramFiles, 'Microsoft Visual Studio');
+ potentialMsvsPaths.push(...computePossiblePaths(parentPath));
+ }
+
+ for (const potentialPath of potentialMsvsPaths) {
+ const wholePath = path.join(potentialPath, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat');
+ console.log("checking", wholePath);
+ if (await exists(wholePath)) {
+ vcvarsallPath = wholePath;
+ break;
+ }
+ }
+
+ if (!vcvarsallPath) {
+ throw new Error(`vcvarsall.bat not found`);
+ }
}
let vcTarget;
- switch (vsBuildArch) {
- case "x64": {
+ switch (targetArch) {
+ case "x64":
vcTarget = "VC-WIN64A";
break;
- }
- case "x86": {
+ case "x86":
vcTarget = "VC-WIN32";
break;
- }
-
- default: {
- throw new Error(`Unknown vsBuildArch: ${vsBuildArch}`);
- }
+
+ case "arm64":
+ vcTarget = "VC-WIN64-ARM";
+ break;
}
- await execPromise(`"${win32BatPath}" "${vcvarsallPath}" ${vsBuildArch} ${vcTarget}`, {
- cwd: buildCwd,
- maxBuffer: 10 * 1024 * 1024 // we should really just use spawn
- }, { pipeOutput: true });
+ let vsBuildArch = hostArch === targetArch
+ ? hostArch
+ : `${hostArch}_${targetArch}`;
+
+ console.log("Using vcvarsall.bat at: ", vcvarsallPath);
+ console.log("Using vsBuildArch: ", vsBuildArch);
+ console.log("Using vcTarget: ", vcTarget);
+
+ await new Promise((resolve, reject) => {
+ const buildProcess = spawn(`"${win32BatPath}" "${vcvarsallPath}" ${vsBuildArch} ${vcTarget}`, {
+ cwd: buildCwd,
+ shell: process.platform === "win32",
+ env: {
+ ...process.env,
+ NODEGIT_SKIP_TESTS: targetArch !== hostArch ? "1" : undefined
+ }
+ });
+
+ buildProcess.stdout.on("data", function(data) {
+ console.info(data.toString().trim());
+ });
+
+ buildProcess.stderr.on("data", function(data) {
+ console.error(data.toString().trim());
+ });
+
+ buildProcess.on("close", function(code) {
+ if (!code) {
+ resolve();
+ } else {
+ reject(code);
+ }
+ });
+ });
+
+
};
const removeOpenSSLIfOudated = async (openSSLVersion) => {
@@ -235,8 +334,7 @@ const makeOnStreamDownloadProgress = () => {
const buildOpenSSLIfNecessary = async ({
macOsDeploymentTarget,
- openSSLVersion,
- vsBuildArch
+ openSSLVersion
}) => {
if (process.platform !== "darwin" && process.platform !== "win32" && process.platform !== "linux") {
console.log(`Skipping OpenSSL build, not required on ${process.platform}`);
@@ -259,7 +357,7 @@ const buildOpenSSLIfNecessary = async ({
const openSSLUrl = getOpenSSLSourceUrl(openSSLVersion);
const openSSLSha256Url = getOpenSSLSourceSha256Url(openSSLVersion);
- const openSSLSha256 = (await got(openSSLSha256Url)).body.trim();
+ const openSSLSha256 = (await got(openSSLSha256Url)).body.trim().split(' ')[0];
const downloadStream = got.stream(openSSLUrl);
downloadStream.on("downloadProgress", makeOnStreamDownloadProgress());
@@ -280,7 +378,7 @@ const buildOpenSSLIfNecessary = async ({
} else if (process.platform === "linux") {
await buildLinux(buildCwd);
} else if (process.platform === "win32") {
- await buildWin32(buildCwd, vsBuildArch);
+ await buildWin32(buildCwd);
} else {
throw new Error(`Unknown platform: ${process.platform}`);
}
@@ -332,18 +430,17 @@ const downloadOpenSSLIfNecessary = async ({
console.log("Download finished.");
}
-const getOpenSSLPackageName = () => {
- let arch = process.arch;
- if (process.platform === "win32" && (
- process.arch === "ia32" || process.env.NODEGIT_VS_BUILD_ARCH === "x86"
- )) {
- arch = "x86";
- }
-
- return `openssl-${OPENSSL_VERSION}-${process.platform}-${arch}.tar.gz`;
+export const getOpenSSLPackageName = () => {
+ return `openssl-${OPENSSL_VERSION}-${process.platform}-${targetArch}.tar.gz`;
}
-const getOpenSSLPackageUrl = () => `${packageJson.binary.host}${getOpenSSLPackageName()}`;
+export const getOpenSSLPackagePath = () => path.join(import.meta.dirname, getOpenSSLPackageName());
+
+const getOpenSSLPackageUrl = () => {
+ const hostUrl = new URL(packageJson.binary.host);
+ hostUrl.pathname = getOpenSSLPackageName();
+ return hostUrl.toString();
+};
const buildPackage = async () => {
let resolve, reject;
@@ -366,10 +463,10 @@ const buildPackage = async () => {
new HashVerify("sha256", (digest) => {
resolve(digest);
}),
- createWriteStream(getOpenSSLPackageName())
+ createWriteStream(getOpenSSLPackagePath())
);
const digest = await promise;
- await fs.writeFile(`${getOpenSSLPackageName()}.sha256`, digest);
+ await fs.writeFile(`${getOpenSSLPackagePath()}.sha256`, digest);
};
const acquireOpenSSL = async () => {
@@ -392,24 +489,15 @@ const acquireOpenSSL = async () => {
let macOsDeploymentTarget;
if (process.platform === "darwin") {
- macOsDeploymentTarget = process.argv[2];
+ macOsDeploymentTarget = process.argv[2] ?? process.env.OPENSSL_MACOS_DEPLOYMENT_TARGET
if (!macOsDeploymentTarget || !macOsDeploymentTarget.match(/\d+\.\d+/)) {
throw new Error(`Invalid macOsDeploymentTarget: ${macOsDeploymentTarget}`);
}
}
- let vsBuildArch;
- if (process.platform === "win32") {
- vsBuildArch = process.env.NODEGIT_VS_BUILD_ARCH || (process.arch === "x64" ? "x64" : "x86");
- if (!["x64", "x86"].includes(vsBuildArch)) {
- throw new Error(`Invalid vsBuildArch: ${vsBuildArch}`);
- }
- }
-
await buildOpenSSLIfNecessary({
openSSLVersion: OPENSSL_VERSION,
- macOsDeploymentTarget,
- vsBuildArch
+ macOsDeploymentTarget
});
if (process.env.NODEGIT_OPENSSL_BUILD_PACKAGE) {
await buildPackage();
@@ -427,5 +515,5 @@ if (process.argv[1] === import.meta.filename) {
catch(error) {
console.error("Acquire OpenSSL failed: ", error);
process.exit(1);
- };
+ }
}
diff --git a/utils/build-openssl.bat b/utils/build-openssl.bat
index 6e146cf89..af8063d7c 100644
--- a/utils/build-openssl.bat
+++ b/utils/build-openssl.bat
@@ -1,9 +1,18 @@
+rem Build OpenSSL for Windows
+rem %1 - path to vcvarsall.bat
+rem %2 - architecture argument for vcvarsall.bat
+rem %3 - OpenSSL Configure target
+
@call %1 %2
perl .\Configure %3 no-shared no-ssl2 no-ssl3 no-comp --prefix="%cd%\.." --openssldir="%cd%\.." || goto :error
nmake || goto :error
-nmake test || goto :error
+
+if "%NODEGIT_SKIP_TESTS%" NEQ "1" (
+ nmake test || goto :error
+)
+
nmake install || goto :error
goto :EOF
diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp
index a155fb67f..f141e4d2d 100644
--- a/vendor/libgit2.gyp
+++ b/vendor/libgit2.gyp
@@ -315,13 +315,22 @@
# Workaround of a strange bug:
# TargetMachine + static_library + x64 = nothing.
"conditions": [
- ["target_arch=='x64'", {
- "VCLibrarianTool": {
- "AdditionalOptions": [
- "/MACHINE:X64",
- ],
+ [
+ "target_arch=='x64'", {
+ "VCLibrarianTool": {
+ "AdditionalOptions": [
+ "/MACHINE:X64",
+ ],
+ },
+ },
+ "target_arch=='arm64'", {
+ "VCLibrarianTool": {
+ "AdditionalOptions": [
+ "/MACHINE:ARM64",
+ ],
+ },
},
- }, {
+ {
"VCLibrarianTool": {
"AdditionalOptions": [
"/MACHINE:x86",
diff --git a/vendor/patches/openssl/001-linux-force_getentropy_dso_lookup.patch b/vendor/patches/openssl/001-linux-force_getentropy_dso_lookup.patch
deleted file mode 100644
index 6802c7fa5..000000000
--- a/vendor/patches/openssl/001-linux-force_getentropy_dso_lookup.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-openssl doesn't have any sort of guard around this section of code other than
-checking if we're compiling an elf binary on gnu linux. the syscall wrapper
-`getentropy` is only available on glibc >= 2.25 which is a problem if we want
-to support platforms like centos7 which ships with glibc 2.17. Attempting to
-load this code on centos7 causes a runtime "undefined symbol error since glibc
-doesn't provide it.
-luckily openssl provides a backup lookup method in form of a dlopen call but
-theres no way to configure for it, hence this patch.
-Note further that centos7 doesn't have this function or the syscall it wraps
-so the symbol lookup will fail and it will fallback to reading from /dev/random.
-hence this patch just fixes compilation.
-author: JZA
---- crypto/rand/rand_unix.c
-+++ crypto/rand/rand_unix.c
-@@ -372,7 +372,7 @@ static ssize_t syscall_random(void *buf, size_t buflen)
- * Note: Sometimes getentropy() can be provided but not implemented
- * internally. So we need to check errno for ENOSYS
- */
--# if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux)
-+# if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux) && 0
- extern int getentropy(void *buffer, size_t length) __attribute__((weak));
-
- if (getentropy != NULL) {