Skip to content

Commit e20a378

Browse files
Exclude NOTICE files from binary detection to reduce unnecessary installation prompts
1 parent a1efed9 commit e20a378

1 file changed

Lines changed: 40 additions & 50 deletions

File tree

lib/installers.js

Lines changed: 40 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const fs = require("fs");
22
const path = require("path");
33
const os = require("os");
4-
const { execSync } = require("child_process");
4+
const { safeExecSync } = require("./utils");
55
const { extractName } = require("./config");
66

77
const getPlatformInfo = () => {
@@ -53,7 +53,7 @@ const getPlatformInfo = () => {
5353
const getInstallCapabilities = () => {
5454
const ebool = (cmd) => {
5555
try {
56-
return execSync(cmd, { stdio: "ignore" }).length > 0;
56+
return safeExecSync(cmd, [], { stdio: "ignore" }).length > 0;
5757
} catch (e) {
5858
return false;
5959
}
@@ -165,30 +165,19 @@ const selectBestAsset = (assets, platformInfo, capabilities) => {
165165
const extractArchive = (filePath, outputDir, extension) => {
166166
switch (extension) {
167167
case "tar.gz":
168-
execSync(
169-
`tar -xzf ${JSON.stringify(filePath)} --directory ${JSON.stringify(
170-
outputDir
171-
)}`
172-
);
168+
safeExecSync("tar", ["-xzf", filePath, "--directory", outputDir]);
173169
break;
174170
case "tar.xz":
175-
execSync(
176-
`tar -xJf ${JSON.stringify(filePath)} --directory ${JSON.stringify(
177-
outputDir
178-
)}`
179-
);
171+
safeExecSync("tar", ["-xJf", filePath, "--directory", outputDir]);
172+
break;
173+
case "tar.bz2":
174+
safeExecSync("tar", ["-xjf", filePath, "--directory", outputDir]);
180175
break;
181176
case "zip":
182-
execSync(
183-
`unzip ${JSON.stringify(filePath)} -d ${JSON.stringify(outputDir)}`
184-
);
177+
safeExecSync("unzip", [filePath, "-d", outputDir]);
185178
break;
186179
case "tar.zst":
187-
execSync(
188-
`unzstd < ${JSON.stringify(filePath)} | tar -xf - --directory ${JSON.stringify(
189-
outputDir
190-
)}`
191-
);
180+
safeExecSync("sh", ["-c", `unzstd < ${JSON.stringify(filePath)} | tar -xf - --directory ${JSON.stringify(outputDir)}`]);
192181
break;
193182
default:
194183
// For files without known extensions, just copy them
@@ -201,10 +190,8 @@ const getBinaries = (dir) => {
201190
// First, find .app directories (these are app bundles on macOS)
202191
let appDirectories = [];
203192
try {
204-
appDirectories = execSync(
205-
`find ${JSON.stringify(
206-
path.resolve(dir)
207-
)} -maxdepth 2 -type d -name "*.app"`
193+
appDirectories = safeExecSync(
194+
"find", [path.resolve(dir), "-maxdepth", "2", "-type", "d", "-name", "*.app"]
208195
)
209196
.toString()
210197
.split("\n")
@@ -217,8 +204,8 @@ const getBinaries = (dir) => {
217204
}
218205

219206
// Then find all files
220-
const allFiles = execSync(
221-
`find ${JSON.stringify(path.resolve(dir))} -type f ! -size 0`
207+
const allFiles = safeExecSync(
208+
"find", [path.resolve(dir), "-type", "f", "!", "-size", "0"]
222209
)
223210
.toString()
224211
.split("\n")
@@ -247,7 +234,7 @@ const getBinaries = (dir) => {
247234
}
248235

249236
const filePath = path.resolve(dir, f);
250-
const fileOutput = execSync(`file ${JSON.stringify(filePath)}`).toString();
237+
const fileOutput = safeExecSync("file", [filePath]).toString();
251238

252239
// Check if it's an executable binary or script
253240
return fileOutput.includes("executable") ||
@@ -274,11 +261,12 @@ const getBinaries = (dir) => {
274261
if (filename.includes("readme") || filename.includes("license") ||
275262
filename.includes("changelog") || filename.includes("copying") ||
276263
filename.includes("install") || filename.includes("makefile") ||
277-
filename.includes(".md") || filename.includes(".txt") ||
278-
filename.includes(".1") || filename.includes(".json") ||
279-
filename.includes(".yaml") || filename.includes(".yml") ||
280-
filename.includes(".toml") || filename.includes(".cfg") ||
281-
filename.includes(".conf") || filename.includes(".ini")) {
264+
filename.includes("notice") || filename.includes(".md") ||
265+
filename.includes(".txt") || filename.includes(".1") ||
266+
filename.includes(".json") || filename.includes(".yaml") ||
267+
filename.includes(".yml") || filename.includes(".toml") ||
268+
filename.includes(".cfg") || filename.includes(".conf") ||
269+
filename.includes(".ini")) {
282270
return false;
283271
}
284272

@@ -319,6 +307,7 @@ const selectBinaries = async (binaries, packageName, logger = null, yesFlag = fa
319307
return !filename.includes('readme') &&
320308
!filename.includes('license') &&
321309
!filename.includes('changelog') &&
310+
!filename.includes('notice') &&
322311
!filename.includes('.md') &&
323312
!filename.includes('.txt') &&
324313
!filename.includes('.1') && // man pages
@@ -487,13 +476,20 @@ const installApp = async (appPath, outputDir, checkPathFn, logger = null, yesFla
487476
const dest = path.join("/Applications", `${cleaned}.app`);
488477
await checkPathFn(dest);
489478

490-
fs.cpSync(path.join(outputDir, appPath), dest, { recursive: true });
479+
// Use rsync to preserve all file attributes, permissions, and symlinks
480+
try {
481+
safeExecSync("rsync", ["-a", "--copy-links", "--protect-args", `${path.join(outputDir, appPath)}/`, dest]);
482+
} catch (e) {
483+
// Fallback to fs.cpSync if rsync fails
484+
if (logger) {
485+
logger.warn(`rsync failed, falling back to fs.cpSync: ${e.message}`);
486+
}
487+
fs.cpSync(path.join(outputDir, appPath), dest, { recursive: true, preserveTimestamps: true });
488+
}
491489

492490
// Code sign
493491
try {
494-
execSync(
495-
`codesign --sign - --force --deep ${JSON.stringify(dest)} 2> /dev/null`
496-
);
492+
safeExecSync("codesign", ["--sign", "-", "--force", "--deep", dest], { stdio: "pipe" });
497493
if (logger) {
498494
logger.debug(`Successfully codesigned ${dest}`);
499495
}
@@ -505,9 +501,7 @@ const installApp = async (appPath, outputDir, checkPathFn, logger = null, yesFla
505501

506502
// Remove quarantine
507503
try {
508-
execSync(
509-
`xattr -rd com.apple.quarantine ${JSON.stringify(dest)} 2> /dev/null`
510-
);
504+
safeExecSync("xattr", ["-rd", "com.apple.quarantine", dest], { stdio: "pipe" });
511505
if (logger) {
512506
logger.debug(`Removed quarantine from ${dest}`);
513507
}
@@ -521,7 +515,7 @@ const installApp = async (appPath, outputDir, checkPathFn, logger = null, yesFla
521515
};
522516

523517
const installPkg = (pkgPath) => {
524-
execSync(`sudo installer -pkg ${JSON.stringify(pkgPath)} -target /`);
518+
safeExecSync("sudo", ["installer", "-pkg", pkgPath, "-target", "/"]);
525519
return ["System-wide package installation"];
526520
};
527521

@@ -533,11 +527,7 @@ const mountDMG = (dmgPath, mountPoint, logger = null) => {
533527
}
534528
fs.mkdirSync(mountPoint, { recursive: true });
535529

536-
execSync(
537-
`hdiutil attach ${JSON.stringify(
538-
dmgPath
539-
)} -nobrowse -mountpoint ${JSON.stringify(mountPoint)}`
540-
);
530+
safeExecSync("hdiutil", ["attach", dmgPath, "-nobrowse", "-mountpoint", mountPoint]);
541531

542532
if (!fs.existsSync(mountPoint)) {
543533
throw new Error(
@@ -555,7 +545,7 @@ const mountDMG = (dmgPath, mountPoint, logger = null) => {
555545

556546
const ejectDMG = (mountPoint, logger = null) => {
557547
try {
558-
execSync(`hdiutil eject ${JSON.stringify(mountPoint)}`);
548+
safeExecSync("hdiutil", ["eject", mountPoint]);
559549
if (logger) {
560550
logger.debug(`Successfully ejected DMG at: ${mountPoint}`);
561551
}
@@ -567,7 +557,7 @@ const ejectDMG = (mountPoint, logger = null) => {
567557
}
568558
// Try force eject as fallback
569559
try {
570-
execSync(`hdiutil eject ${JSON.stringify(mountPoint)} -force`);
560+
safeExecSync("hdiutil", ["eject", mountPoint, "-force"]);
571561
if (logger) {
572562
logger.debug(`Force ejected DMG at: ${mountPoint}`);
573563
}
@@ -600,7 +590,7 @@ const installBinaries = async (
600590
// Don't try to chmod files on mounted volumes (like DMGs)
601591
if (!isMountedVolume) {
602592
try {
603-
execSync(`chmod +x ${JSON.stringify(binaryPath)}`);
593+
safeExecSync("chmod", ["+x", binaryPath]);
604594
} catch (e) {
605595
if (logger) {
606596
logger.warn(`Failed to make ${binary} executable: ${e.message}`);
@@ -612,7 +602,7 @@ const installBinaries = async (
612602

613603
// Make sure the copied file is executable
614604
try {
615-
execSync(`chmod +x ${JSON.stringify(dest)}`);
605+
safeExecSync("chmod", ["+x", dest]);
616606
} catch (e) {
617607
if (logger) {
618608
logger.warn(`Failed to make copied binary executable: ${e.message}`);
@@ -626,7 +616,7 @@ const installBinaries = async (
626616
};
627617

628618
const installDeb = (debPath) => {
629-
execSync(`sudo dpkg -i ${JSON.stringify(debPath)}`);
619+
safeExecSync("sudo", ["dpkg", "-i", debPath]);
630620
return ["System-wide deb installation"];
631621
};
632622

0 commit comments

Comments
 (0)