Skip to content

Commit 23df6a1

Browse files
committed
feat: build.osx.target to specify dmg, zip or both
Closes #322
1 parent 0ac4596 commit 23df6a1

File tree

7 files changed

+82
-36
lines changed

7 files changed

+82
-36
lines changed

docs/Options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ See all [appdmg options](https://www.npmjs.com/package/appdmg#json-specification
7070
| --- | ---
7171
| icon | <a name="OsXBuildOptions-icon"></a>The path to icon, which will be shown when mounted (default: `build/icon.icns`).
7272
| background | <a name="OsXBuildOptions-background"></a>The path to background (default: `build/background.png`).
73+
| target | <a name="OsXBuildOptions-target"></a>Target package type: list of `default`, `dmg`, `zip`.
7374

7475
<a name="WinBuildOptions"></a>
7576
### `.build.win`

src/build-cli.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const cli = cla([
2121
{name: "publish", type: String, alias: "p", description: "Publish artifacts (to GitHub Releases): onTag (on tag push only) or onTagOrDraft (on tag push or if draft release exists)."},
2222
{name: "platform", type: String, multiple: true, description: "darwin, linux, win32 or all. Current platform (" + process.platform + ") by default."},
2323
{name: "arch", type: String, description: "ia32, x64 or all. Defaults to architecture you're running on."},
24-
{name: "target", type: String, multiple: true, description: "Installer or package type."},
2524
{name: "sign", type: String},
2625
{name: "help", alias: "h", type: Boolean, description: "Display this usage guide."},
2726
{name: "appDir", type: String}

src/macPackager.ts

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ import { PlatformPackager, BuildInfo } from "./platformPackager"
22
import { Platform, OsXBuildOptions } from "./metadata"
33
import * as path from "path"
44
import { Promise as BluebirdPromise } from "bluebird"
5-
import { log, spawn } from "./util"
5+
import { log, spawn, statOrNull } from "./util"
66
import { createKeychain, deleteKeychain, CodeSigningInfo, generateKeychainName, sign } from "./codeSign"
7-
import { stat } from "fs-extra-p"
87
import { path7za } from "7zip-bin"
98
import deepAssign = require("deep-assign")
109

1110
//noinspection JSUnusedLocalSymbols
1211
const __awaiter = require("./awaiter")
1312

14-
export default class MacPackager extends PlatformPackager<OsXBuildOptions> {
13+
export default class OsXPackager extends PlatformPackager<OsXBuildOptions> {
1514
codeSigningInfo: Promise<CodeSigningInfo>
1615

16+
readonly target: Array<string>
17+
1718
constructor(info: BuildInfo, cleanupTasks: Array<() => Promise<any>>) {
1819
super(info)
1920

@@ -25,6 +26,18 @@ export default class MacPackager extends PlatformPackager<OsXBuildOptions> {
2526
else {
2627
this.codeSigningInfo = BluebirdPromise.resolve(null)
2728
}
29+
30+
let target = this.customBuildOptions == null ? null : this.customBuildOptions.target
31+
if (target != null) {
32+
target = Array.isArray(target) ? target : [target]
33+
target = target.map(it => it.toLowerCase().trim())
34+
for (let t of target) {
35+
if (t !== "default" && t !== "dmg" && t !== "zip") {
36+
throw new Error("Unknown target: " + t)
37+
}
38+
}
39+
}
40+
this.target = target == null ? ["default"] : target
2841
}
2942

3043
get platform() {
@@ -68,13 +81,9 @@ export default class MacPackager extends PlatformPackager<OsXBuildOptions> {
6881

6982
if (this.customBuildOptions == null || !("background" in this.customBuildOptions)) {
7083
const background = path.join(this.buildResourcesDir, "background.png")
71-
try {
72-
if ((await stat(background)).isFile()) {
73-
specification.background = background
74-
}
75-
}
76-
catch (e) {
77-
// ignored
84+
const info = await statOrNull(background)
85+
if (info != null && info.isFile()) {
86+
specification.background = background
7887
}
7988
}
8089

@@ -84,8 +93,10 @@ export default class MacPackager extends PlatformPackager<OsXBuildOptions> {
8493

8594
packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise<any> {
8695
const artifactPath = path.join(appOutDir, `${this.appName}-${this.metadata.version}.dmg`)
87-
return BluebirdPromise.all([
88-
new BluebirdPromise<any>(async (resolve, reject) => {
96+
const promises: Array<Promise<any>> = []
97+
98+
if (this.target.includes("dmg") || this.target.includes("default")) {
99+
promises.push(new BluebirdPromise<any>(async(resolve, reject) => {
89100
log("Creating DMG")
90101
const emitter = require("appdmg")({
91102
target: artifactPath,
@@ -95,11 +106,15 @@ export default class MacPackager extends PlatformPackager<OsXBuildOptions> {
95106
emitter.on("error", reject)
96107
emitter.on("finish", () => resolve())
97108
})
98-
.then(() => this.dispatchArtifactCreated(artifactPath, `${this.metadata.name}-${this.metadata.version}.dmg`)),
109+
.then(() => this.dispatchArtifactCreated(artifactPath, `${this.metadata.name}-${this.metadata.version}.dmg`)))
110+
}
111+
112+
if (this.target.includes("zip") || this.target.includes("default")) {
113+
promises.push(this.zipMacApp(appOutDir)
114+
.then(it => this.dispatchArtifactCreated(it, `${this.metadata.name}-${this.metadata.version}-mac.zip`)))
115+
}
99116

100-
this.zipMacApp(appOutDir)
101-
.then(it => this.dispatchArtifactCreated(it, `${this.metadata.name}-${this.metadata.version}-mac.zip`))
102-
])
117+
return BluebirdPromise.all(promises)
103118
}
104119

105120
private zipMacApp(outDir: string): Promise<string> {

src/metadata.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export interface Metadata {
2-
readonly repository: string | RepositoryInfo
2+
readonly repository?: string | RepositoryInfo
33
}
44

55
/*
@@ -138,7 +138,7 @@ export interface BuildMetadata {
138138
*/
139139
readonly compression?: "store" | "normal" | "maximum"
140140

141-
readonly "build-version": string
141+
readonly "build-version"?: string
142142
}
143143

144144
/*
@@ -156,6 +156,11 @@ export interface OsXBuildOptions extends PlatformSpecificBuildOptions {
156156
The path to background (default: `build/background.png`).
157157
*/
158158
readonly background?: string
159+
160+
/*
161+
Target package type: list of `default`, `dmg`, `zip`.
162+
*/
163+
readonly target?: Array<string>
159164
}
160165

161166
/*

src/platformPackager.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export interface PackagerOptions {
2424
sign?: string
2525

2626
platform?: Array<Platform>
27-
target?: Array<string>
2827

2928
// deprecated
3029
appDir?: string

test/src/helpers/packTester.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ if (process.env.TRAVIS !== "true") {
2424
export const outDirName = "dist"
2525

2626
interface AssertPackOptions {
27+
readonly useTempDir?: boolean
2728
readonly tempDirCreated?: (projectDir: string) => Promise<any>
2829
readonly packed?: (projectDir: string) => Promise<any>
2930
readonly expectedContents?: Array<string>
3031
}
3132

3233
export async function assertPack(fixtureName: string, packagerOptions: PackagerOptions, checkOptions?: AssertPackOptions): Promise<void> {
3334
const tempDirCreated = checkOptions == null ? null : checkOptions.tempDirCreated
34-
const useTempDir = tempDirCreated != null || packagerOptions.target != null
35+
const useTempDir = tempDirCreated != null || packagerOptions.devMetadata != null
3536

3637
let projectDir = path.join(__dirname, "..", "..", "fixtures", fixtureName)
3738
// const isDoNotUseTempDir = platform === "darwin"
@@ -102,7 +103,7 @@ async function packAndCheck(projectDir: string, packagerOptions: PackagerOptions
102103

103104
for (let platform of packagerOptions.platform) {
104105
if (platform === Platform.OSX) {
105-
await checkOsXResult(packager, artifacts.get(Platform.OSX))
106+
await checkOsXResult(packager, checkOptions, artifacts.get(Platform.OSX))
106107
}
107108
else if (platform === Platform.LINUX) {
108109
await checkLinuxResult(projectDir, packager, packagerOptions)
@@ -165,7 +166,7 @@ function parseDebControl(info: string): any {
165166
return metadata
166167
}
167168

168-
async function checkOsXResult(packager: Packager, artifacts: Array<ArtifactCreated>) {
169+
async function checkOsXResult(packager: Packager, checkOptions: AssertPackOptions, artifacts: Array<ArtifactCreated>) {
169170
const productName = getProductName(packager.metadata, packager.devMetadata)
170171
const packedAppDir = path.join(path.dirname(artifacts[0].file), (productName || packager.metadata.name) + ".app")
171172
const info = parsePlist(await readFile(path.join(packedAppDir, "Contents", "Info.plist"), "utf8"))
@@ -179,15 +180,21 @@ async function checkOsXResult(packager: Packager, artifacts: Array<ArtifactCreat
179180
const result = await exec("codesign", ["--verify", packedAppDir])
180181
assertThat(result[0].toString()).not.match(/is not signed at all/)
181182

182-
assertThat(artifacts.map(it => path.basename(it.file)).sort()).deepEqual([
183-
`${productName}-1.1.0-mac.zip`,
184-
`${productName}-1.1.0.dmg`,
185-
].sort())
186-
187-
assertThat(artifacts.map(it => it.artifactName).sort()).deepEqual([
188-
"TestApp-1.1.0-mac.zip",
189-
"TestApp-1.1.0.dmg",
190-
].sort())
183+
const actualFiles = artifacts.map(it => path.basename(it.file)).sort()
184+
if (checkOptions != null && checkOptions.expectedContents != null) {
185+
assertThat(actualFiles).deepEqual(checkOptions.expectedContents)
186+
}
187+
else {
188+
assertThat(actualFiles).deepEqual([
189+
`${productName}-1.1.0-mac.zip`,
190+
`${productName}-1.1.0.dmg`,
191+
].sort())
192+
193+
assertThat(artifacts.map(it => it.artifactName).sort()).deepEqual([
194+
"TestApp-1.1.0-mac.zip",
195+
"TestApp-1.1.0.dmg",
196+
].sort())
197+
}
191198
}
192199

193200
async function checkWindowsResult(packager: Packager, packagerOptions: PackagerOptions, checkOptions: AssertPackOptions, artifacts: Array<ArtifactCreated>) {

test/src/osxPackagerTest.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import test from "./helpers/avaEx"
22
import { assertPack, platform, modifyPackageJson } from "./helpers/packTester"
33
import { Platform } from "out"
4-
import MacPackager from "out/macPackager"
4+
import OsXPackager from "out/macPackager"
55
import { move } from "fs-extra-p"
66
import * as path from "path"
77
import { BuildInfo } from "out/platformPackager"
@@ -11,12 +11,32 @@ import * as assertThat from "should/as-function"
1111
//noinspection JSUnusedLocalSymbols
1212
const __awaiter = require("out/awaiter")
1313

14-
test.ifOsx("mac: two-package.json", () => assertPack("test-app", {
14+
test.ifOsx("two-package.json", () => assertPack("test-app", {
1515
platform: [Platform.OSX],
1616
arch: "all",
1717
}))
1818

19-
test.ifOsx("mac: one-package.json", () => assertPack("test-app-one", platform(Platform.OSX)))
19+
test.ifOsx("one-package.json", () => assertPack("test-app-one", platform(Platform.OSX)))
20+
21+
function createTargetTest(target: string, expectedContents: Array<string>) {
22+
return () => assertPack("test-app-one", {
23+
platform: [Platform.OSX],
24+
devMetadata: {
25+
build: {
26+
osx: {
27+
target: [target]
28+
}
29+
}
30+
}
31+
}, {
32+
useTempDir: true,
33+
expectedContents: expectedContents
34+
})
35+
}
36+
37+
test.ifOsx("only dmg", createTargetTest("dmg", ["TestApp-1.1.0.dmg"]))
38+
test.ifOsx("only zip", createTargetTest("zip", ["TestApp-1.1.0-mac.zip"]))
39+
test.ifOsx("invalid target", (t: any) => t.throws(createTargetTest("ttt", [])(), "Unknown target: ttt"))
2040

2141
// test.ifOsx("no background", (t: any) => assertPack("test-app-one", platform(Platform.OSX), {
2242
// tempDirCreated: projectDir => deleteFile(path.join(projectDir, "build", "background.png"))
@@ -46,7 +66,7 @@ test.ifOsx("custom background", () => {
4666
})
4767
})
4868

49-
class CheckingOsXPackager extends MacPackager {
69+
class CheckingOsXPackager extends OsXPackager {
5070
effectiveDistOptions: any
5171

5272
constructor(info: BuildInfo, cleanupTasks: Array<() => Promise<any>>) {

0 commit comments

Comments
 (0)