diff --git a/.changeset/stupid-lobsters-own.md b/.changeset/stupid-lobsters-own.md new file mode 100644 index 00000000000..e540a1e1959 --- /dev/null +++ b/.changeset/stupid-lobsters-own.md @@ -0,0 +1,5 @@ +--- +"app-builder-lib": patch +--- + +fix: detecting workspace root for calculating whether a relative file is within the project directory due to monorepo workspaces having `process.cwd()` returning the subpackage instead of monorepo root diff --git a/packages/app-builder-lib/package.json b/packages/app-builder-lib/package.json index 1322b70ed95..9550b43ac1e 100644 --- a/packages/app-builder-lib/package.json +++ b/packages/app-builder-lib/package.json @@ -66,6 +66,7 @@ "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "workspace:*", + "find-up": "^5.0.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", @@ -104,6 +105,7 @@ "@babel/preset-react": "7.24.7", "@types/debug": "4.1.7", "@types/ejs": "3.1.0", + "@types/find-up": "^4.0.2", "@types/hosted-git-info": "3.0.2", "@types/js-yaml": "4.0.3", "@types/plist": "3.0.5", diff --git a/packages/app-builder-lib/src/asar/asarUtil.ts b/packages/app-builder-lib/src/asar/asarUtil.ts index fcdca3ac8a7..93d03d54298 100644 --- a/packages/app-builder-lib/src/asar/asarUtil.ts +++ b/packages/app-builder-lib/src/asar/asarUtil.ts @@ -9,6 +9,8 @@ import { PlatformPackager } from "../platformPackager" import { ResolvedFileSet, getDestinationPath } from "../util/appFileCopier" import { detectUnpackedDirs } from "./unpackDetector" import { Readable } from "stream" +import * as findUp from "find-up" +import { readdir } from "fs/promises" /** @internal */ export class AsarPackager { @@ -143,8 +145,9 @@ export class AsarPackager { return { path: destination, streamGenerator, unpacked, type: "file", stat: { mode: stat.mode, size } } } + const rootDir = (await findWorkspaceRoot(fileSet.src)) ?? fileSet.src const realPathFile = await fs.realpath(file) - const realPathRelative = path.relative(fileSet.src, realPathFile) + const realPathRelative = path.relative(rootDir, realPathFile) const isOutsidePackage = realPathRelative.startsWith("..") if (isOutsidePackage) { log.error({ source: log.filePath(file), realPathFile: log.filePath(realPathFile) }, `unable to copy, file is symlinked outside the package`) @@ -159,7 +162,7 @@ export class AsarPackager { } // not a symlink, stream directly - if (file === realPathFile) { + if (!stat.isSymbolicLink()) { return { ...config, type: "file", @@ -231,3 +234,33 @@ export class AsarPackager { } } } + +export async function findWorkspaceRoot(startDir: string): Promise { + const packageJson = "package.json" + const WORKSPACE_MARKERS = ["pnpm-workspace.yaml", "lerna.json", "nx.json", "turbo.json", ".yarnrc.yml", packageJson] + // Use findUp to search for workspace markers in parent directories + const file = await findUp( + async directory => { + const dirContents = await readdir(directory) + const pkgJsonPath = path.join(directory, packageJson) + + for (const filenameMarker of WORKSPACE_MARKERS) { + if (dirContents.includes(filenameMarker)) { + if (filenameMarker === packageJson) { + const rootWorkspaceConfigPath = await fs + .readJson(pkgJsonPath) + .then(pkg => (pkg.workspaces || pkg.pnpm || pkg.workspaces?.packages ? pkgJsonPath : undefined)) + .catch(() => undefined) // ignore invalid package.json + if (rootWorkspaceConfigPath) { + return rootWorkspaceConfigPath + } + } + return path.join(directory, filenameMarker) + } + } + return dirContents.includes(".git") ? findUp.stop : undefined // stop searching if we hit a .git root directory + }, + { cwd: startDir } + ) + return file ? path.dirname(file) : undefined +} diff --git a/packages/app-builder-lib/src/node-module-collector/yarnNodeModulesCollector.ts b/packages/app-builder-lib/src/node-module-collector/yarnNodeModulesCollector.ts index c2c882c898b..8d2dca1cf11 100644 --- a/packages/app-builder-lib/src/node-module-collector/yarnNodeModulesCollector.ts +++ b/packages/app-builder-lib/src/node-module-collector/yarnNodeModulesCollector.ts @@ -6,6 +6,5 @@ export class YarnNodeModulesCollector extends NpmNodeModulesCollector { super(rootDir) } - // note: do not override instance-var `pmCommand`. We explicitly use npm for the json payload public readonly installOptions = { manager: PM.YARN, lockfile: "yarn.lock" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9821ac73bd..97393c4f0b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -155,6 +155,9 @@ importers: electron-publish: specifier: workspace:* version: link:../electron-publish + find-up: + specifier: ^5.0.0 + version: 5.0.0 fs-extra: specifier: ^10.1.0 version: 10.1.0 @@ -261,6 +264,9 @@ importers: '@types/ejs': specifier: 3.1.0 version: 3.1.0 + '@types/find-up': + specifier: ^4.0.2 + version: 4.0.2 '@types/hosted-git-info': specifier: 3.0.2 version: 3.0.2 @@ -2251,6 +2257,10 @@ packages: '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/find-up@4.0.2': + resolution: {integrity: sha512-AcxsY79jbVkizdp5BPS9jsMntFD9GTbQJp+HgSvzFvDIL0dgfy1TRHpyQxZkPkgp5oIK0lnaJ8m+qSZhBMIqbw==} + deprecated: This is a stub types definition. find-up provides its own type definitions, so you do not need this installed. + '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} @@ -7827,6 +7837,10 @@ snapshots: '@types/estree@1.0.7': {} + '@types/find-up@4.0.2': + dependencies: + find-up: 5.0.0 + '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4