mirror of
https://github.com/whyour/qinglong.git
synced 2026-11-02 15:56:59 +08:00
fix: preserve npm environment during package replacement
This commit is contained in:
@@ -28,5 +28,47 @@ function restorePackageLock(root = path.resolve(__dirname, '..')) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { restorePackageLock };
|
||||
if (require.main === module) restorePackageLock();
|
||||
function restoreEnvironment(root = path.resolve(__dirname, '..')) {
|
||||
// npm's Arborist keeps this exact retirement directory until lifecycle scripts
|
||||
// succeed, then deletes it. Never search other installations or sibling backups.
|
||||
const suffix = createHash('sha1').update(root).digest('base64')
|
||||
.replace(/[^a-zA-Z0-9]+/g, '').slice(0, 8);
|
||||
const retired = path.join(path.dirname(root), `.${path.basename(root)}-${suffix}`);
|
||||
const destination = path.join(root, '.env');
|
||||
const exists = (file) => {
|
||||
try { return fs.lstatSync(file); }
|
||||
catch (error) { if (error.code === 'ENOENT') return; throw error; }
|
||||
};
|
||||
if (exists(destination)) return;
|
||||
const directory = exists(retired);
|
||||
if (!directory) return;
|
||||
if (!directory.isDirectory()) throw new Error('Invalid npm retirement directory');
|
||||
const metadata = path.join(retired, 'package.json');
|
||||
if (!exists(metadata)?.isFile()) throw new Error('Invalid retired npm package');
|
||||
if (JSON.parse(fs.readFileSync(metadata, 'utf8')).name !== '@whyour/qinglong')
|
||||
throw new Error('Unexpected retired npm package');
|
||||
const source = path.join(retired, '.env');
|
||||
const stat = exists(source);
|
||||
if (!stat) return;
|
||||
if (!stat.isFile()) throw new Error('Retired npm .env must be a regular file');
|
||||
const descriptor = fs.openSync(source, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
||||
const temporary = path.join(root, `.upgrade-env-${randomUUID()}`);
|
||||
try {
|
||||
if (!fs.fstatSync(descriptor).isFile()) throw new Error('Invalid retired npm .env');
|
||||
fs.writeFileSync(temporary, fs.readFileSync(descriptor), { flag: 'wx', mode: 0o600 });
|
||||
// Linking publishes a complete file without replacing a concurrently created .env.
|
||||
try { fs.linkSync(temporary, destination); }
|
||||
catch (error) { if (error.code !== 'EEXIST') throw error; }
|
||||
} finally {
|
||||
fs.closeSync(descriptor);
|
||||
fs.rmSync(temporary, { force: true });
|
||||
}
|
||||
}
|
||||
|
||||
function installPackage(root = path.resolve(__dirname, '..')) {
|
||||
restorePackageLock(root);
|
||||
restoreEnvironment(root);
|
||||
}
|
||||
|
||||
module.exports = { restorePackageLock, restoreEnvironment, installPackage };
|
||||
if (require.main === module) installPackage();
|
||||
|
||||
Reference in New Issue
Block a user