Skip to content

Commit 726e574

Browse files
committed
fix: Build failing when productName contains a slash
Close #539
1 parent bb71621 commit 726e574

File tree

13 files changed

+57
-58
lines changed

13 files changed

+57
-58
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"debug": "^2.2.0",
6868
"deep-assign": "^2.0.0",
6969
"electron-osx-sign-tf": "0.6.0",
70-
"electron-packager-tf": "~7.4.0",
70+
"electron-packager-tf": "~7.5.1",
7171
"electron-winstaller-fixed": "~2.11.5",
7272
"fs-extra-p": "^1.0.3",
7373
"hosted-git-info": "^2.1.5",

src/appInfo.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { warn } from "./util/log"
44
import { smarten } from "./platformPackager"
55
import { isEmptyOrSpaces } from "./util/util"
66
import { getRepositoryInfo } from "./repositoryInfo"
7+
import sanitizeFileName = require("sanitize-filename")
78

89
//noinspection JSUnusedLocalSymbols
910
const __awaiter = require("./util/awaiter")
@@ -23,6 +24,8 @@ export class AppInfo {
2324
readonly version: string
2425
readonly buildVersion: string
2526

27+
readonly productFilename: string
28+
2629
constructor(public metadata: AppMetadata, private devMetadata: DevMetadata) {
2730
let buildVersion = metadata.version
2831
this.version = buildVersion
@@ -32,6 +35,8 @@ export class AppInfo {
3235
buildVersion += `.${buildNumber}`
3336
}
3437
this.buildVersion = buildVersion
38+
39+
this.productFilename = sanitizeFileName(this.productName)
3540
}
3641

3742
get companyName() {

src/macPackager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export default class MacPackager extends PlatformPackager<MacOptions> {
166166
const identity = codeSigningInfo.name
167167

168168
const baseSignOptions: BaseSignOptions = {
169-
app: path.join(appOutDir, `${this.appInfo.productName}.app`),
169+
app: path.join(appOutDir, `${this.appInfo.productFilename}.app`),
170170
platform: masOptions == null ? "darwin" : "mas",
171171
keychain: <any>codeSigningInfo.keychainName,
172172
version: this.info.electronVersion
@@ -202,7 +202,7 @@ export default class MacPackager extends PlatformPackager<MacOptions> {
202202
await task(`Signing app (identity: ${identity})`, this.doSign(signOptions))
203203

204204
if (masOptions != null) {
205-
const pkg = path.join(appOutDir, `${this.appInfo.productName}-${this.appInfo.version}.pkg`)
205+
const pkg = path.join(appOutDir, `${this.appInfo.productFilename}-${this.appInfo.version}.pkg`)
206206
await this.doFlat(Object.assign({
207207
pkg: pkg,
208208
identity: codeSigningInfo.installerName,

src/platformPackager.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
8181
readonly projectDir: string
8282
readonly buildResourcesDir: string
8383

84-
readonly metadata: AppMetadata
8584
readonly devMetadata: DevMetadata
8685

8786
readonly platformSpecificBuildOptions: DC
@@ -96,7 +95,6 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
9695
this.appInfo = info.appInfo
9796
this.options = info.options
9897
this.projectDir = info.projectDir
99-
this.metadata = info.appInfo.metadata
10098
this.devMetadata = info.devMetadata
10199

102100
this.buildResourcesDir = path.resolve(this.projectDir, this.relativeBuildResourcesDirname)
@@ -299,7 +297,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
299297
}
300298

301299
private async doCopyExtraFiles(isResources: boolean, appOutDir: string, arch: Arch, customBuildOptions: DC): Promise<any> {
302-
const base = isResources ? this.getResourcesDir(appOutDir) : this.platform === Platform.MAC ? path.join(appOutDir, `${this.appInfo.productName}.app`, "Contents") : appOutDir
300+
const base = isResources ? this.getResourcesDir(appOutDir) : this.platform === Platform.MAC ? path.join(appOutDir, `${this.appInfo.productFilename}.app`, "Contents") : appOutDir
303301
const patterns = this.getFilePatterns(isResources ? "extraResources" : "extraFiles", customBuildOptions)
304302
return patterns == null || patterns.length === 0 ? null : copyFiltered(this.projectDir, base, createFilter(this.projectDir, this.getParsedPatterns(patterns, arch)))
305303
}
@@ -334,7 +332,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
334332
}
335333

336334
private getOSXResourcesDir(appOutDir: string): string {
337-
return path.join(appOutDir, `${this.appInfo.productName}.app`, "Contents", "Resources")
335+
return path.join(appOutDir, `${this.appInfo.productFilename}.app`, "Contents", "Resources")
338336
}
339337

340338
private async checkFileInPackage(resourcesDir: string, file: string, isAsar: boolean) {
@@ -363,12 +361,12 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
363361
throw new Error(`Output directory "${appOutDir}" is not a directory. Seems like a wrong configuration.`)
364362
}
365363

366-
const mainFile = this.metadata.main || "index.js"
364+
const mainFile = this.appInfo.metadata.main || "index.js"
367365
await this.checkFileInPackage(this.getResourcesDir(appOutDir), mainFile, isAsar)
368366
}
369367

370368
protected async archiveApp(format: string, appOutDir: string, outFile: string): Promise<any> {
371-
return archiveApp(this.devMetadata.build.compression, format, outFile, this.platform === Platform.MAC ? path.join(appOutDir, `${this.appInfo.productName}.app`) : appOutDir)
369+
return archiveApp(this.devMetadata.build.compression, format, outFile, this.platform === Platform.MAC ? path.join(appOutDir, `${this.appInfo.productFilename}.app`) : appOutDir)
372370
}
373371

374372
generateName(ext: string, arch: Arch, deployment: boolean): string {
@@ -387,7 +385,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
387385
}
388386

389387
generateName2(ext: string, classifier: string | n, deployment: boolean): string {
390-
return `${deployment ? this.appInfo.name : this.appInfo.productName}-${this.metadata.version}${classifier == null ? "" : `-${classifier}`}.${ext}`
388+
return `${deployment ? this.appInfo.name : this.appInfo.productFilename}-${this.appInfo.version}${classifier == null ? "" : `-${classifier}`}.${ext}`
391389
}
392390

393391
protected async getDefaultIcon(ext: string) {

src/targets/dmg.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class DmgTarget extends Target {
3333

3434
async build(appOutDir: string) {
3535
const appInfo = this.packager.appInfo
36-
const artifactPath = path.join(appOutDir, `${appInfo.productName}-${appInfo.version}.dmg`)
36+
const artifactPath = path.join(appOutDir, `${appInfo.productFilename}-${appInfo.version}.dmg`)
3737
await new BluebirdPromise<any>(async(resolve, reject) => {
3838
log("Creating DMG")
3939
const dmgOptions = {
@@ -78,7 +78,7 @@ export class DmgTarget extends Target {
7878
}
7979
}
8080

81-
specification.contents[1].path = path.join(appOutDir, `${packager.appInfo.productName}.app`)
81+
specification.contents[1].path = path.join(appOutDir, `${packager.appInfo.productFilename}.app`)
8282
return specification
8383
}
8484
}

src/targets/fpm.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class FpmTarget extends Target {
8888

8989
const templateOptions = Object.assign({
9090
// old API compatibility
91-
executable: this.packager.appInfo.productName,
91+
executable: this.packager.appInfo.productFilename,
9292
}, this.packager.platformSpecificBuildOptions)
9393

9494
const afterInstallTemplate = this.packager.platformSpecificBuildOptions.afterInstall || path.join(defaultTemplatesDir, "after-install.tpl")
@@ -111,7 +111,7 @@ export class FpmTarget extends Target {
111111
}
112112

113113
const options = this.options
114-
const author = options.maintainer || `${packager.metadata.author.name} <${packager.metadata.author.email}>`
114+
const author = options.maintainer || `${packager.appInfo.metadata.author.name} <${packager.appInfo.metadata.author.email}>`
115115
const synopsis = options.synopsis
116116
const args = [
117117
"-s", "dir",
@@ -163,28 +163,28 @@ export class FpmTarget extends Target {
163163
args.push("--depends", dep)
164164
}
165165

166-
use(packager.metadata.license || packager.devMetadata.license, it => args.push("--license", it!))
166+
use(packager.appInfo.metadata.license || packager.devMetadata.license, it => args.push("--license", it!))
167167
use(appInfo.buildNumber, it => args.push("--iteration", it!))
168168

169169
use(options.fpm, it => args.push(...<any>it))
170170

171-
args.push(`${appOutDir}/=${installPrefix}/${appInfo.productName}`)
171+
args.push(`${appOutDir}/=${installPrefix}/${appInfo.productFilename}`)
172172
args.push(...<any>(await this.packageFiles)!)
173173
await exec(await this.fpmPath, args)
174174
}
175175

176176
private async computeDesktop(tempDir: string): Promise<Array<string>> {
177177
const appInfo = this.packager.appInfo
178-
const tempFile = path.join(tempDir, appInfo.productName + ".desktop")
178+
const tempFile = path.join(tempDir, `${appInfo.productFilename}.desktop`)
179179
await outputFile(tempFile, this.packager.platformSpecificBuildOptions.desktop || `[Desktop Entry]
180180
Name=${appInfo.productName}
181181
Comment=${this.packager.platformSpecificBuildOptions.description || appInfo.description}
182-
Exec="${installPrefix}/${appInfo.productName}/${appInfo.productName}"
182+
Exec="${installPrefix}/${appInfo.productFilename}/${appInfo.productFilename}"
183183
Terminal=false
184184
Type=Application
185185
Icon=${appInfo.name}
186186
`)
187-
return [`${tempFile}=/usr/share/applications/${appInfo.productName}.desktop`]
187+
return [`${tempFile}=/usr/share/applications/${appInfo.productFilename}.desktop`]
188188
}
189189

190190
private async createFromIcns(tempDir: string): Promise<Array<string>> {

src/targets/nsis.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { Target } from "../platformPackager"
99
import { archiveApp } from "./archive"
1010
import { subTask, task } from "../util/log"
1111
import { unlink } from "fs-extra-p"
12-
import sanitizeFileName = require("sanitize-filename")
1312
import semver = require("semver")
1413

1514
//noinspection JSUnusedLocalSymbols
@@ -53,15 +52,14 @@ export default class NsisTarget extends Target {
5352
const iconPath = await packager.getIconPath()
5453
const appInfo = packager.appInfo
5554
const version = appInfo.version
56-
const installerPath = path.join(this.outDir, `${appInfo.productName} Setup ${version}.exe`)
55+
const installerPath = path.join(this.outDir, `${appInfo.productFilename} Setup ${version}.exe`)
5756

5857
const guid = this.options.guid || await BluebirdPromise.promisify(uuid5)({namespace: ELECTRON_BUILDER_NS_UUID, name: appInfo.id})
59-
const productName = appInfo.productName
6058
const defines: any = {
6159
APP_ID: appInfo.id,
6260
APP_GUID: guid,
63-
PRODUCT_NAME: productName,
64-
INST_DIR_NAME: sanitizeFileName(productName),
61+
PRODUCT_NAME: appInfo.productName,
62+
INST_DIR_NAME: appInfo.productFilename,
6563
APP_DESCRIPTION: appInfo.description,
6664
VERSION: version,
6765

src/targets/squirrelWindows.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default class SquirrelWindowsTarget extends Target {
2323
const appInfo = this.packager.appInfo
2424
const version = appInfo.version
2525
const archSuffix = getArchSuffix(arch)
26-
const setupFileName = `${appInfo.productName} Setup ${version}${archSuffix}.exe`
26+
const setupFileName = `${appInfo.productFilename} Setup ${version}${archSuffix}.exe`
2727

2828
const installerOutDir = path.join(appOutDir, "..", `win${getArchSuffix(arch)}`)
2929
await emptyDir(installerOutDir)
@@ -45,7 +45,7 @@ export default class SquirrelWindowsTarget extends Target {
4545
const packager = this.packager
4646
let iconUrl = packager.platformSpecificBuildOptions.iconUrl || packager.devMetadata.build.iconUrl
4747
if (iconUrl == null) {
48-
const info = await getRepositoryInfo(packager.metadata, packager.devMetadata)
48+
const info = await getRepositoryInfo(packager.appInfo.metadata, packager.devMetadata)
4949
if (info != null) {
5050
iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${packager.relativeBuildResourcesDirname}/icon.ico?raw=true`
5151
}
@@ -69,7 +69,7 @@ export default class SquirrelWindowsTarget extends Target {
6969
const options: any = Object.assign({
7070
name: appInfo.name,
7171
productName: appInfo.productName,
72-
exe: `${appInfo.productName}.exe`,
72+
exe: `${appInfo.productFilename}.exe`,
7373
setupExe: setupExeName,
7474
msiExe: setupExeName.replace(".exe", ".msi"),
7575
title: appInfo.productName,

src/winPackager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
103103
const packOptions = await this.computePackOptions(outDir, appOutDir, arch)
104104

105105
await this.doPack(packOptions, outDir, appOutDir, arch, this.platformSpecificBuildOptions)
106-
await this.sign(path.join(appOutDir, `${this.appInfo.productName}.exe`))
106+
await this.sign(path.join(appOutDir, `${this.appInfo.productFilename}.exe`))
107107
this.packageInDistributableFormat(outDir, appOutDir, arch, targets, postAsyncTasks)
108108
}
109109

test/fixtures/test-app-one/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"name": "TestApp",
4-
"productName": "Test App",
4+
"productName": "Test App A/B",
55
"version": "1.1.0",
66
"homepage": "http://foo.example.com",
77
"description": "Test Application (test quite \" #378)",

0 commit comments

Comments
 (0)