mirror of
https://github.com/whyour/qinglong.git
synced 2026-11-06 07:10:41 +08:00
fix: preserve legacy SQLite addons loaded from build directories
This commit is contained in:
@@ -211,15 +211,25 @@ async function prestartBackend(
|
||||
}
|
||||
|
||||
async function cleanSqliteBuildArtifacts(directory) {
|
||||
const names = await fs.readdir(directory).catch((error) => {
|
||||
const entries = await fs.readdir(directory, { withFileTypes: true }).catch((error) => {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
return [];
|
||||
});
|
||||
// node-pre-gyp's runtime copy lives in lib/binding. Its build directories
|
||||
// retain compiler objects and an absolute node_gyp_bins/python3 symlink.
|
||||
for (const name of names)
|
||||
if (name === 'build' || /^build-tmp-napi-v\d+$/.test(name))
|
||||
await fs.rm(path.join(directory, name), { recursive: true, force: true });
|
||||
if (!entries.length) return;
|
||||
const pkg = JSON.parse(await fs.readFile(path.join(directory, 'package.json'), 'utf8'));
|
||||
const runtimePath = path.posix.normalize(pkg.binary?.module_path || '.');
|
||||
const copiedRuntime = runtimePath.startsWith('lib/binding/');
|
||||
// Our legacy fork copies its runtime to lib/binding. Other sqlite3 versions
|
||||
// load build/Release directly: retain that addon and remove only the compiler
|
||||
// helper directory. Never traverse a build-directory symlink while cleaning.
|
||||
for (const entry of entries) {
|
||||
if (entry.name !== 'build' && !/^build-tmp-napi-v\d+$/.test(entry.name)) continue;
|
||||
const build = path.join(directory, entry.name);
|
||||
await fs.rm(
|
||||
copiedRuntime || entry.isSymbolicLink() ? build : path.join(build, 'node_gyp_bins'),
|
||||
{ recursive: true, force: true },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function repairDependencies(source, { target, signal, env }) {
|
||||
|
||||
@@ -37,7 +37,7 @@ async function fixture(t) {
|
||||
await fs.mkdir(path.join(root, name), { recursive: true });
|
||||
await fs.writeFile(root + '/package.json', JSON.stringify({ qinglongMigrationBridge: { format: 1 }, dependencies: { sqlite3: 'legacy' } }));
|
||||
await fs.writeFile(root + '/pnpm-lock.yaml', 'fixed legacy lock');
|
||||
await fs.writeFile(root + '/node_modules/sqlite3/package.json', '{}');
|
||||
await fs.writeFile(root + '/node_modules/sqlite3/package.json', JSON.stringify({ binary: { module_path: './lib/binding/napi-v{napi_build_version}-{platform}-{arch}' } }));
|
||||
await fs.writeFile(root + '/runtime/include/node/node_version.h', '#define NODE_MAJOR_VERSION 24\n#define NODE_MINOR_VERSION 18\n#define NODE_PATCH_VERSION 1\n');
|
||||
return { root, runtime: { execPath: root + '/runtime/bin/node', versions: { node: '24.18.1' }, env: { PATH: '/qa/bin', NODE_OPTIONS: '--require=untrusted', CFLAGS: '-march=armv7' } } };
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const {
|
||||
dependencyFailure,
|
||||
probeLimits,
|
||||
repairDependencies,
|
||||
cleanSqliteBuildArtifacts,
|
||||
} = require('../../cli/src/internal/maintenance/upgradePrestart.cjs');
|
||||
|
||||
for (const exitCode of [0, 1])
|
||||
@@ -291,7 +292,7 @@ test('successful legacy repair publishes only portable runtime files from a pnpm
|
||||
const pkg = 'node_modules/.pnpm/@whyour+sqlite3@1.1.2/node_modules/@whyour/sqlite3';
|
||||
if (process.argv[2] === 'install') {
|
||||
fs.mkdirSync(pkg + '/lib/binding/napi-v6-linux-arm', {recursive:true});
|
||||
fs.writeFileSync(pkg + '/package.json', '{}');
|
||||
fs.writeFileSync(pkg + '/package.json', JSON.stringify({binary:{module_path:'./lib/binding/napi-v{napi_build_version}-{platform}-{arch}'}}));
|
||||
fs.symlinkSync('.pnpm/@whyour+sqlite3@1.1.2/node_modules/@whyour/sqlite3', 'node_modules/sqlite3');
|
||||
} else if (process.argv[2] === 'rebuild') {
|
||||
fs.writeFileSync(pkg + '/lib/binding/napi-v6-linux-arm/node_sqlite3.node', 'compiled addon');
|
||||
@@ -331,6 +332,26 @@ test('successful legacy repair publishes only portable runtime files from a pnpm
|
||||
await inventory({ source });
|
||||
});
|
||||
|
||||
test('cleanup retains sqlite3 runtimes loaded from build/Release and never follows a build symlink', async (t) => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'ql-sqlite-release-'));
|
||||
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
||||
const sqlite = path.join(root, 'sqlite3'), outside = path.join(root, 'outside');
|
||||
await fs.mkdir(path.join(sqlite, 'build/Release'), { recursive: true });
|
||||
await fs.mkdir(path.join(sqlite, 'build/node_gyp_bins'));
|
||||
await fs.mkdir(path.join(outside, 'node_gyp_bins'), { recursive: true });
|
||||
await fs.writeFile(path.join(outside, 'node_gyp_bins/keep'), 'untouched');
|
||||
await fs.writeFile(path.join(sqlite, 'package.json'), JSON.stringify({ name: 'sqlite3', binary: { napi_versions: [3, 6] } }));
|
||||
await fs.writeFile(path.join(sqlite, 'build/Release/node_sqlite3.node'), 'runtime addon');
|
||||
await fs.symlink('/usr/bin/python3', path.join(sqlite, 'build/node_gyp_bins/python3'));
|
||||
await fs.symlink(outside, path.join(sqlite, 'build-tmp-napi-v3'));
|
||||
await cleanSqliteBuildArtifacts(sqlite);
|
||||
assert.equal(await fs.readFile(path.join(sqlite, 'build/Release/node_sqlite3.node'), 'utf8'), 'runtime addon');
|
||||
await assert.rejects(fs.access(path.join(sqlite, 'build/node_gyp_bins')), { code: 'ENOENT' });
|
||||
await assert.rejects(fs.lstat(path.join(sqlite, 'build-tmp-napi-v3')), { code: 'ENOENT' });
|
||||
assert.equal(await fs.readFile(path.join(outside, 'node_gyp_bins/keep'), 'utf8'), 'untouched');
|
||||
await require('../../cli/src/internal/maintenance/platformBundle.cjs').inventory({ source: sqlite });
|
||||
});
|
||||
|
||||
test('repair classification excludes application, platform, config, database, OOM and timeouts', () => {
|
||||
for (const error of [
|
||||
{ code: 'MODULE_NOT_FOUND', message: "Cannot find module './api/missing'" },
|
||||
|
||||
Reference in New Issue
Block a user