diff --git a/package.json b/package.json index 5de515450..3eb1617d8 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ }, "scripts": { "lint": "eslint ./src/**/*.js ./test/**/*.js", - "lint:fix": "eslint --fix ./**/*.{js,md} && markdownlint --fix ./README.md", + "lint:fix": "eslint --fix ./src/**/*.js ./test/**/*.js", + "markdown:fix": "markdownlint --fix ./README.md", "docs": "jsdoc -d docs ./README.md ./src/index.js ./src/get.js ./src/run.js ./src/bld.js", "test": "vitest run", "demo": "cd test/fixture && node demo.js" diff --git a/src/get/decompress.js b/src/get/decompress.js index 5a284a605..928c69ae2 100644 --- a/src/get/decompress.js +++ b/src/get/decompress.js @@ -47,31 +47,50 @@ function modeFromEntry(entry) { */ async function unzip(zippedFile, cacheDir) { const zip = await yauzl.open(zippedFile); - let entry = await zip.readEntry(); + const symlinks = []; // Array to hold symbolic link entries while (entry !== null) { let entryPathAbs = path.join(cacheDir, entry.filename); - /* Create the directory beforehand to prevent `ENOENT: no such file or directory` errors. */ - await fs.promises.mkdir(path.dirname(entryPathAbs), { recursive: true }); - /* Check if entry is a symbolic link */ + // Check if entry is a symbolic link const isSymlink = ((modeFromEntry(entry) & 0o170000) === 0o120000); - const readStream = await entry.openReadStream(); - + if (isSymlink) { - const chunks = []; - /* Read stream into Array. */ - readStream.on("data", (chunk) => chunks.push(chunk)); - await stream.promises.finished(readStream); - const link = Buffer.concat(chunks).toString('utf8').trim(); - await fs.promises.symlink(link, entryPathAbs) + // Store symlink entries to process later + symlinks.push(entry); } else { - // Pipe read to write stream - const writeStream = fs.createWriteStream(entryPathAbs); - await stream.promises.pipeline(readStream, writeStream); + // Handle regular files and directories + await fs.promises.mkdir(path.dirname(entryPathAbs), {recursive: true}); + if (!entry.filename.endsWith('/')) { // Skip directories + const readStream = await entry.openReadStream(); + const writeStream = fs.createWriteStream(entryPathAbs); + await stream.promises.pipeline(readStream, writeStream); + + // Set file permissions after the file has been written + const mode = modeFromEntry(entry); + await fs.promises.chmod(entryPathAbs, mode); + } } // Read next entry entry = await zip.readEntry(); } + + // Process symbolic links after all other files have been extracted + for (const symlinkEntry of symlinks) { + let entryPathAbs = path.join(cacheDir, symlinkEntry.filename); + const readStream = await symlinkEntry.openReadStream(); + const chunks = []; + readStream.on("data", (chunk) => chunks.push(chunk)); + await new Promise(resolve => readStream.on("end", resolve)); + const linkTarget = Buffer.concat(chunks).toString('utf8').trim(); + + // Check if the symlink or a file/directory already exists at the destination + if (fs.existsSync(entryPathAbs)) { + //skip + } else { + // Create symbolic link + await fs.promises.symlink(linkTarget, entryPathAbs); + } + } } diff --git a/src/get/index.js b/src/get/index.js index a8f8d5f00..eccb75c57 100644 --- a/src/get/index.js +++ b/src/get/index.js @@ -97,7 +97,7 @@ async function get(options) { */ let ffmpegFilePath = path.resolve( options.cacheDir, - `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}.zip`, + `ffmpeg-${options.version}-${options.platform}-${options.arch}.zip`, ); // If `options.cache` is false, then remove the compressed binary. @@ -115,7 +115,10 @@ async function get(options) { */ const ffmpegFilePathExists = await util.fileExists(ffmpegFilePath); if (ffmpegFilePathExists === false) { - ffmpegFilePath = await ffmpeg(options.downloadUrl, options.version, options.platform, options.arch, options.cacheDir); + // Do not update the options.downloadUrl with the ffmpeg URL here. Doing so would lead to error when options.ffmpeg and options.nativeAddon are both enabled. + const downloadUrl = + "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"; + ffmpegFilePath = await ffmpeg(downloadUrl, options.version, options.platform, options.arch, options.cacheDir); } await decompress(ffmpegFilePath, options.cacheDir);