Skip to content
This repository has been archived by the owner on Jan 13, 2024. It is now read-only.

Commit

Permalink
fix: allow copyFile and copyFileSync from snapshot (#1484)
Browse files Browse the repository at this point in the history
Co-authored-by: Nikolai Kolodziej <7687617+kldzj@users.noreply.github.com>
Co-authored-by: Jesse Chan <jc@linux.com>
  • Loading branch information
3 people authored Feb 3, 2022
1 parent 37cc27e commit 72bc8b3
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 13 deletions.
103 changes: 90 additions & 13 deletions prelude/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,28 @@ function createMountpoint(interior, exterior) {
mountpoints.push({ interior, exterior });
}

function copyFileSync(source, target) {
let targetFile = target;

// If target is a directory, a new file with the same name will be created
if (fs.existsSync(target)) {
if (fs.lstatSync(target).isDirectory()) {
targetFile = path.join(target, path.basename(source));
}
const DEFAULT_COPY_CHUNK_SIZE = 10 * 1024 * 1024; // 10 MB
function copyInChunks(
source,
target,
chunkSize = DEFAULT_COPY_CHUNK_SIZE,
fs_ = fs
) {
const sourceFile = fs_.openSync(source, 'r');
const targetFile = fs_.openSync(target, 'w');

let bytesRead = 1;
while (bytesRead > 0) {
const buffer = Buffer.alloc(chunkSize);
bytesRead = fs_.readSync(sourceFile, buffer, 0, chunkSize);
fs_.writeSync(targetFile, buffer, 0, bytesRead);
}

fs.writeFileSync(targetFile, fs.readFileSync(source));
fs_.closeSync(sourceFile);
fs_.closeSync(targetFile);
}

// TODO: replace this with fs.cpSync when we drop Node < 16
function copyFolderRecursiveSync(source, target) {
let files = [];

Expand All @@ -188,7 +197,10 @@ function copyFolderRecursiveSync(source, target) {
if (fs.lstatSync(curSource).isDirectory()) {
copyFolderRecursiveSync(curSource, targetFolder);
} else {
copyFileSync(curSource, targetFolder);
fs.copyFileSync(
curSource,
path.join(targetFolder, path.basename(curSource))
);
}
});
}
Expand Down Expand Up @@ -572,6 +584,8 @@ function payloadFileSync(pointer) {
mkdirSync: fs.mkdirSync,
mkdir: fs.mkdir,
createReadStream: fs.createReadStream,
copyFileSync: fs.copyFileSync,
copyFile: fs.copyFile,
};

ancestor.realpathSync.native = fs.realpathSync;
Expand Down Expand Up @@ -1066,6 +1080,67 @@ function payloadFileSync(pointer) {
});
};

fs.copyFile = function copyFile(src, dest, flags, callback) {
if (!insideSnapshot(path.resolve(src))) {
ancestor.copyFile(src, dest, flags, callback);
return;
}
if (typeof flags === 'function') {
callback = flags;
flags = 0;
} else if (typeof callback !== 'function') {
throw new TypeError('Callback must be a function');
}

function _streamCopy() {
fs.createReadStream(src)
.on('error', callback)
.pipe(fs.createWriteStream(dest))
.on('error', callback)
.on('finish', callback);
}

if (flags & fs.constants.COPYFILE_EXCL) {
fs.stat(dest, (statError) => {
if (!statError) {
callback(
Object.assign(new Error('File already exists'), {
code: 'EEXIST',
})
);
return;
}
if (statError.code !== 'ENOENT') {
callback(statError);
return;
}
_streamCopy();
});
} else {
_streamCopy();
}
};

fs.copyFileSync = function copyFileSync(src, dest, flags) {
if (!insideSnapshot(path.resolve(src))) {
ancestor.copyFileSync(src, dest, flags);
return;
}

if (flags & fs.constants.COPYFILE_EXCL) {
try {
fs.statSync(dest);
} catch (statError) {
if (statError.code !== 'ENOENT') throw statError;
copyInChunks(src, dest, DEFAULT_COPY_CHUNK_SIZE, fs);
return;
}

throw Object.assign(new Error('File already exists'), { code: 'EEXIST' });
}
copyInChunks(src, dest, DEFAULT_COPY_CHUNK_SIZE, fs);
};

// ///////////////////////////////////////////////////////////////
// writeFile /////////////////////////////////////////////////////
// ///////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1556,6 +1631,7 @@ function payloadFileSync(pointer) {
lstat: fs.promises.lstat,
fstat: fs.promises.fstat,
access: fs.promises.access,
copyFile: fs.promises.copyFile,
};

fs.promises.open = async function open(path_) {
Expand Down Expand Up @@ -1602,6 +1678,7 @@ function payloadFileSync(pointer) {

// this one use promisify on purpose
fs.promises.readdir = util.promisify(fs.readdir);
fs.promises.copyFile = util.promisify(fs.copyFile);

/*
fs.promises.read = util.promisify(fs.read);
Expand Down Expand Up @@ -2093,6 +2170,8 @@ function payloadFileSync(pointer) {
// Example: /tmp/pkg/<hash>
const tmpFolder = path.join(tmpdir(), 'pkg', hash);

createDirRecursively(tmpFolder);

// Example: moduleFolder = /snapshot/appname/node_modules/sharp/build/Release
const parts = moduleFolder.split(path.sep);
const mIndex = parts.indexOf('node_modules') + 1;
Expand All @@ -2110,14 +2189,12 @@ function payloadFileSync(pointer) {
// here we copy all files from the snapshot module folder to temporary folder
// we keep the module folder structure to prevent issues with modules that are statically
// linked using relative paths (Fix #1075)
createDirRecursively(tmpFolder);
copyFolderRecursiveSync(modulePkgFolder, tmpFolder);

// Example: /tmp/pkg/<hash>/sharp/build/Release/sharp.node
newPath = path.join(tmpFolder, modulePackagePath, moduleBaseName);
} else {
createDirRecursively(tmpFolder);
copyFileSync(modulePath, tmpFolder);
fs.copyFileSync(modulePath, path.join(tmpFolder, moduleBaseName));

// load the copied file in the temporary folder
newPath = path.join(tmpFolder, moduleBaseName);
Expand Down
3 changes: 3 additions & 0 deletions test/test-420-copy-from-snapshot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output
sync.json
async.json
19 changes: 19 additions & 0 deletions test/test-420-copy-from-snapshot/copy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env node

'use strict';

const fs = require('fs');
const path = require('path');

const testPath = path.resolve(__dirname, 'input/test.json');
console.log(fs.readFileSync(testPath, 'utf8'));

const syncPath = path.resolve(process.cwd(), 'output/sync.json');
fs.copyFileSync(testPath, syncPath);
console.log(fs.readFileSync(syncPath, 'utf8'));

const asyncPath = path.resolve(process.cwd(), 'output/async.json');
fs.copyFile(testPath, asyncPath, (err) => {
if (err) throw err;
console.log(fs.readFileSync(asyncPath, 'utf8'));
});
3 changes: 3 additions & 0 deletions test/test-420-copy-from-snapshot/input/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"key": "value"
}
30 changes: 30 additions & 0 deletions test/test-420-copy-from-snapshot/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env node

'use strict';

const path = require('path');
const assert = require('assert');
const utils = require('../utils.js');

assert(!module.parent);
assert(__dirname === process.cwd());

const target = process.argv[2] || 'host';
const input = './copy.js';
const output = './output/test-output.exe';

utils.mkdirp.sync(path.dirname(output));
utils.pkg.sync(['--target', target, '--output', output, '.']);

let left, right;
left = utils.spawn.sync('node', [path.basename(input)], {
cwd: path.dirname(input),
});

right = utils.spawn.sync(output, [], {
cwd: path.dirname(input),
});

assert.strictEqual(left, right);
utils.vacuum.sync(path.dirname(output));
utils.vacuum.sync(path.join(__dirname, '/*sync.json'));
8 changes: 8 additions & 0 deletions test/test-420-copy-from-snapshot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"bin": "copy.js",
"pkg": {
"assets": [
"input/**/*"
]
}
}

0 comments on commit 72bc8b3

Please sign in to comment.