diff --git a/src/platformPackager.ts b/src/platformPackager.ts index 4ddd11ebd38..9abb253bda9 100644 --- a/src/platformPackager.ts +++ b/src/platformPackager.ts @@ -154,8 +154,17 @@ export abstract class PlatformPackager abstract pack(outDir: string, arch: Arch, targets: Array, postAsyncTasks: Array>): Promise + private getExtraFilePatterns(isResources: boolean, arch: Arch, customBuildOptions: DC): Array | null { + const patterns = this.getFilePatterns(isResources ? "extraResources" : "extraFiles", customBuildOptions) + return patterns == null || patterns.length === 0 ? null : this.getParsedPatterns(patterns, arch) + } + protected async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, platformName: string, arch: Arch, platformSpecificBuildOptions: DC) { const asarOptions = this.computeAsarOptions(platformSpecificBuildOptions) + + const extraResourcePatterns = this.getExtraFilePatterns(true, arch, platformSpecificBuildOptions) + const extraFilePatterns = this.getExtraFilePatterns(false, arch, platformSpecificBuildOptions) + const p = pack(options, appOutDir, platformName, Arch[arch], this.info.electronVersion, async() => { const ignoreFiles = new Set([path.relative(this.info.appDir, outDir), path.relative(this.info.appDir, this.buildResourcesDir)]) if (!this.info.isTwoPackageJsonProjectLayoutUsed) { @@ -196,8 +205,24 @@ export abstract class PlatformPackager rawFilter = deprecatedUserIgnoreFilter(options, this.info.appDir) } + const filePatterns = this.getParsedPatterns(patterns, arch) + let excludePatterns: Array | null = null + if (!this.info.isTwoPackageJsonProjectLayoutUsed) { + if (extraResourcePatterns != null) { + excludePatterns = extraResourcePatterns + } + if (extraFilePatterns != null) { + if (excludePatterns == null) { + excludePatterns = extraFilePatterns + } + else { + excludePatterns = excludePatterns.concat(extraFilePatterns) + } + } + } + const resourcesPath = this.platform === Platform.MAC ? path.join(appOutDir, "Electron.app", "Contents", "Resources") : path.join(appOutDir, "resources") - const filter = createFilter(this.info.appDir, this.getParsedPatterns(patterns, arch), ignoreFiles, rawFilter) + const filter = createFilter(this.info.appDir, filePatterns, ignoreFiles, rawFilter, excludePatterns) const promise = asarOptions == null ? copyFiltered(this.info.appDir, path.join(resourcesPath, "app"), filter, this.platform === Platform.WINDOWS) : createAsarArchive(this.info.appDir, resourcesPath, asarOptions, filter) @@ -289,8 +314,8 @@ export abstract class PlatformPackager private async doCopyExtraFiles(isResources: boolean, appOutDir: string, arch: Arch, customBuildOptions: DC): Promise { const base = isResources ? this.getResourcesDir(appOutDir) : this.platform === Platform.MAC ? path.join(appOutDir, `${this.appInfo.productFilename}.app`, "Contents") : appOutDir - const patterns = this.getFilePatterns(isResources ? "extraResources" : "extraFiles", customBuildOptions) - return patterns == null || patterns.length === 0 ? null : copyFiltered(this.projectDir, base, createFilter(this.projectDir, this.getParsedPatterns(patterns, arch)), this.platform === Platform.WINDOWS) + const patterns = this.getExtraFilePatterns(isResources, arch, customBuildOptions) + return patterns == null || patterns.length === 0 ? null : copyFiltered(this.projectDir, base, createFilter(this.projectDir, patterns), this.platform === Platform.WINDOWS) } private getParsedPatterns(patterns: Array, arch: Arch): Array { diff --git a/src/util/filter.ts b/src/util/filter.ts index 8d039bc83af..3aefddb3763 100644 --- a/src/util/filter.ts +++ b/src/util/filter.ts @@ -29,7 +29,7 @@ export function hasMagic(pattern: Minimatch) { return false } -export function createFilter(src: string, patterns: Array, ignoreFiles?: Set, rawFilter?: (file: string) => boolean): (file: string) => boolean { +export function createFilter(src: string, patterns: Array, ignoreFiles?: Set, rawFilter?: (file: string) => boolean, excludePatterns?: Array | null): (file: string) => boolean { return function filter(it) { if (src === it) { return true @@ -49,7 +49,8 @@ export function createFilter(src: string, patterns: Array, ignoreFile if (path.sep === "\\") { relative = relative.replace(/\\/g, "/") } - return minimatchAll(relative, patterns) + + return minimatchAll(relative, patterns) && (excludePatterns == null || !minimatchAll(relative, excludePatterns)) } } diff --git a/test/src/globTest.ts b/test/src/globTest.ts index eb52b2c220f..76f965775b2 100644 --- a/test/src/globTest.ts +++ b/test/src/globTest.ts @@ -202,3 +202,84 @@ test("extraResources", async () => { }) } }) + +test("extraResources - one-package", async () => { + for (let platform of [Platform.LINUX]) { + const osName = platform.buildConfigurationKey + + const winDirPrefix = "lib/net45/resources/" + + //noinspection SpellCheckingInspection + await assertPack("test-app-one", { + // to check NuGet package + targets: platform.createTarget(platform === Platform.WINDOWS ? null : DIR_TARGET), + devMetadata: { + build: { + asar: true, + }, + }, + }, { + tempDirCreated: projectDir => { + return BluebirdPromise.all([ + modifyPackageJson(projectDir, data => { + data.build.extraResources = [ + "foo", + "bar/hello.txt", + "bar/${arch}.txt", + "${os}/${arch}.txt", + ] + + data.build[osName] = { + extraResources: [ + "platformSpecificR" + ], + extraFiles: [ + "platformSpecificF" + ], + } + }), + outputFile(path.join(projectDir, "foo/nameWithoutDot"), "nameWithoutDot"), + outputFile(path.join(projectDir, "bar/hello.txt"), "data"), + outputFile(path.join(projectDir, "foo", ".dot"), "data"), + outputFile(path.join(projectDir, `bar/${process.arch}.txt`), "data"), + outputFile(path.join(projectDir, `${osName}/${process.arch}.txt`), "data"), + outputFile(path.join(projectDir, "platformSpecificR"), "platformSpecificR"), + outputFile(path.join(projectDir, "ignoreMe.txt"), "ignoreMe"), + ]) + }, + packed: async (projectDir) => { + const base = path.join(projectDir, outDirName, platform.buildConfigurationKey) + let resourcesDir = path.join(base, "resources") + if (platform === Platform.MAC) { + resourcesDir = path.join(base, "TestApp.app", "Contents", "Resources") + } + else if (platform === Platform.WINDOWS) { + resourcesDir = path.join(base + "-unpacked", "resources") + } + const appDir = path.join(resourcesDir, "app") + + await assertThat(path.join(resourcesDir, "foo")).isDirectory() + await assertThat(path.join(appDir, "foo")).doesNotExist() + + await assertThat(path.join(resourcesDir, "foo", "nameWithoutDot")).isFile() + await assertThat(path.join(appDir, "foo", "nameWithoutDot")).doesNotExist() + + await assertThat(path.join(resourcesDir, "bar", "hello.txt")).isFile() + await assertThat(path.join(resourcesDir, "bar", `${process.arch}.txt`)).isFile() + await assertThat(path.join(appDir, "bar", `${process.arch}.txt`)).doesNotExist() + + await assertThat(path.join(resourcesDir, osName, `${process.arch}.txt`)).isFile() + await assertThat(path.join(resourcesDir, "platformSpecificR")).isFile() + await assertThat(path.join(resourcesDir, "ignoreMe.txt")).doesNotExist() + await assertThat(path.join(resourcesDir, "foo", ".dot")).doesNotExist() + }, + expectedContents: platform === Platform.WINDOWS ? pathSorter(expectedWinContents.concat( + winDirPrefix + "bar/hello.txt", + winDirPrefix + "bar/x64.txt", + winDirPrefix + "foo/nameWithoutDot", + winDirPrefix + "platformSpecificR", + winDirPrefix + "win/x64.txt" + )) : null, + }) + } +})