Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,36 @@ export class App {
async copyTemplate() {
await runHooks(this.opts.beforeCopy, this.hookArgsWithOriginalResourcesAppDir);

await fs.promises.cp(this.opts.dir, this.originalResourcesAppDir, {
const filter = userPathFilter(this.opts)!;
const copyOpts = {
recursive: true,
filter: userPathFilter(this.opts),
filter,
dereference: typeof this.opts.derefSymlinks === 'boolean' ? this.opts.derefSymlinks : true,
});
};

const src = path.resolve(this.opts.dir);
const dest = path.resolve(this.originalResourcesAppDir);
const relativeDest = path.relative(src, dest);
if (
relativeDest &&
relativeDest !== '..' &&
!relativeDest.startsWith(`..${path.sep}`) &&
!path.isAbsolute(relativeDest)
) {
// The destination is inside the app dir (e.g. tmpdir: false with the out dir
// inside the project dir). fs.cp rejects dest-inside-src before the filter runs,
// so copy each top-level entry individually instead.
await fs.promises.mkdir(dest, { recursive: true });
for (const entry of await fs.promises.readdir(src)) {
const srcEntry = path.join(src, entry);
const destEntry = path.join(dest, entry);
if (await filter(srcEntry, destEntry)) {
await fs.promises.cp(srcEntry, destEntry, copyOpts);
}
}
} else {
await fs.promises.cp(this.opts.dir, this.originalResourcesAppDir, copyOpts);
}
await runHooks(this.opts.afterCopy, this.hookArgsWithOriginalResourcesAppDir);
if (this.opts.prune) {
await runHooks(this.opts.afterPrune, this.hookArgsWithOriginalResourcesAppDir);
Expand Down
27 changes: 27 additions & 0 deletions test/packager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,33 @@ describe('packager', () => {
expect(paths[0]).toBeDirectory();
});

// https://github.com/electron/packager/issues/1679
it('can package with tmpdir disabled and the out dir inside the project dir', async ({
baseOpts,
}) => {
const projectDir = path.join(baseOpts.tmpdir as string, 'project');
await fs.promises.cp(baseOpts.dir, projectDir, { recursive: true });

const opts = {
...baseOpts,
dir: projectDir,
out: path.join(projectDir, 'out'),
tmpdir: false,
asar: false,
platform: 'linux',
arch: 'x64',
} as const;

const paths = await packager(opts);
expect(paths).toHaveLength(1);
expect(paths[0]).toBeDirectory();

const appDir = path.join(paths[0], 'resources', 'app');
expect(path.join(appDir, 'main.js')).toBeFile();
// The out dir must not be copied into the packaged app
expect(fs.existsSync(path.join(appDir, 'out'))).toBe(false);
});

it('preserves symlinks with derefSymlinks disabled', async ({ baseOpts }) => {
const opts = {
...baseOpts,
Expand Down
Loading