Skip to content

Commit a3a23f2

Browse files
committed
feat(pkg): build pkg that doesn't require admin install
1 parent 86af4cd commit a3a23f2

File tree

6 files changed

+93
-14
lines changed

6 files changed

+93
-14
lines changed

docs/Options.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,17 @@ Configuration Options
220220
* <a name="DmgOptions-publish"></a>`publish` String | [GithubOptions](Publishing-Artifacts#GithubOptions) | [S3Options](Publishing-Artifacts#S3Options) | [GenericServerOptions](Publishing-Artifacts#GenericServerOptions) | [BintrayOptions](Publishing-Artifacts#BintrayOptions) | Array
221221
* <a name="Config-pkg"></a>`pkg`<a name="PkgOptions"></a> - macOS product archive options.
222222
* <a name="PkgOptions-scripts"></a>`scripts` = `build/pkg-scripts` String - The scripts directory, relative to `build` (build resources directory). The scripts can be in any language so long as the files are marked executable and have the appropriate shebang indicating the path to the interpreter. Scripts are required to be executable (`chmod +x file`). See: [Scripting in installer packages](http://macinstallers.blogspot.de/2012/07/scripting-in-installer-packages.html).
223-
* <a name="PkgOptions-installLocation"></a>`installLocation` = `/Applications` String - The install location.
224-
* <a name="PkgOptions-identity"></a>`identity` String
223+
* <a name="PkgOptions-installLocation"></a>`installLocation` = `/Applications` String - The install location. [Do not use it](https://stackoverflow.com/questions/12863944/how-do-you-specify-a-default-install-location-to-home-with-pkgbuild) to create per-user package. Mostly never you will need to change this option. `/Applications` would install it as expected into `/Applications` if the local system domain is chosen, or into `$HOME/Applications` if the home installation is chosen.
224+
* <a name="PkgOptions-allowAnywhere"></a>`allowAnywhere` = `true` Boolean - Whether can be installed at the root of any volume, including non-system volumes. Otherwise, it cannot be installed at the root of a volume.
225+
226+
Corresponds to [enable_anywhere](https://developer.apple.com/library/content/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW70).
227+
* <a name="PkgOptions-allowCurrentUserHome"></a>`allowCurrentUserHome` = `true` Boolean - Whether can be installed into the current user’s home directory. A home directory installation is done as the current user (not as root), and it cannot write outside of the home directory. If the product cannot be installed in the user’s home directory and be not completely functional from user’s home directory.
228+
229+
Corresponds to [enable_currentUserHome](https://developer.apple.com/library/content/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW70).
230+
* <a name="PkgOptions-allowRootDirectory"></a>`allowRootDirectory` = `true` Boolean - Whether can be installed into the root directory. Should usually be `true` unless the product can be installed only to the user’s home directory.
231+
232+
Corresponds to [enable_localSystem](https://developer.apple.com/library/content/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW70).
233+
* <a name="PkgOptions-identity"></a>`identity` String - The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing) instead of specifying this option.
225234
* <a name="PkgOptions-artifactName"></a>`artifactName` String - The [artifact file name pattern](https://github.com/electron-userland/electron-builder/wiki/Options#artifact-file-name-pattern).
226235
* <a name="PkgOptions-publish"></a>`publish` String | [GithubOptions](Publishing-Artifacts#GithubOptions) | [S3Options](Publishing-Artifacts#S3Options) | [GenericServerOptions](Publishing-Artifacts#GenericServerOptions) | [BintrayOptions](Publishing-Artifacts#BintrayOptions) | Array
227236
* <a name="Config-win"></a>`win`<a name="WinBuildOptions"></a> - Windows options.

packages/electron-builder/src/metadata.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,6 @@ export interface Config extends PlatformSpecificBuildOptions {
269269
*/
270270
readonly dmg?: DmgOptions | null
271271

272-
/**
273-
* macOS product archive options.
274-
*/
275272
readonly pkg?: PkgOptions | null
276273

277274
/**

packages/electron-builder/src/options/macOptions.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ export interface MacOptions extends PlatformSpecificBuildOptions {
7777
readonly requirements?: string | null
7878
}
7979

80+
/**
81+
* macOS product archive options.
82+
*/
8083
export interface PkgOptions extends TargetSpecificOptions {
8184
/**
8285
* The scripts directory, relative to `build` (build resources directory).
@@ -94,11 +97,41 @@ export interface PkgOptions extends TargetSpecificOptions {
9497
readonly productbuild?: Array<string> | null
9598

9699
/**
97-
* The install location.
100+
* The install location. [Do not use it](https://stackoverflow.com/questions/12863944/how-do-you-specify-a-default-install-location-to-home-with-pkgbuild) to create per-user package.
101+
* Mostly never you will need to change this option. `/Applications` would install it as expected into `/Applications` if the local system domain is chosen, or into `$HOME/Applications` if the home installation is chosen.
98102
* @default /Applications
99103
*/
100104
readonly installLocation?: string | null
101105

106+
/**
107+
* Whether can be installed at the root of any volume, including non-system volumes. Otherwise, it cannot be installed at the root of a volume.
108+
*
109+
* Corresponds to [enable_anywhere](https://developer.apple.com/library/content/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW70).
110+
* @default true
111+
*/
112+
readonly allowAnywhere?: boolean | null
113+
114+
/**
115+
* Whether can be installed into the current user’s home directory.
116+
* A home directory installation is done as the current user (not as root), and it cannot write outside of the home directory.
117+
* If the product cannot be installed in the user’s home directory and be not completely functional from user’s home directory.
118+
*
119+
* Corresponds to [enable_currentUserHome](https://developer.apple.com/library/content/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW70).
120+
* @default true
121+
*/
122+
readonly allowCurrentUserHome?: boolean | null
123+
124+
/**
125+
* Whether can be installed into the root directory. Should usually be `true` unless the product can be installed only to the user’s home directory.
126+
*
127+
* Corresponds to [enable_localSystem](https://developer.apple.com/library/content/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW70).
128+
* @default true
129+
*/
130+
readonly allowRootDirectory?: boolean | null
131+
132+
/**
133+
* The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing) instead of specifying this option.
134+
*/
102135
readonly identity?: string | null
103136
}
104137

packages/electron-builder/src/targets/pkg.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import BluebirdPromise from "bluebird-lst"
2-
import { exec, use } from "electron-builder-util"
2+
import { debug, exec, use } from "electron-builder-util"
33
import { statOrNull } from "electron-builder-util/out/fs"
4-
import { unlink } from "fs-extra-p"
4+
import { readFile, unlink, writeFile } from "fs-extra-p"
55
import * as path from "path"
66
import { findIdentity, Identity } from "../codeSign"
77
import { Arch, Target } from "../core"
@@ -11,7 +11,11 @@ import { filterCFBundleIdentifier } from "../packager/mac"
1111

1212
// http://www.shanekirk.com/2013/10/creating-flat-packages-in-osx/
1313
export class PkgTarget extends Target {
14-
readonly options: PkgOptions = this.packager.config.pkg || Object.create(null)
14+
readonly options: PkgOptions = Object.assign({
15+
allowAnywhere: true,
16+
allowCurrentUserHome: true,
17+
allowRootDirectory: true,
18+
}, this.packager.config.pkg)
1519
private readonly installLocation = this.options.installLocation || "/Applications"
1620

1721
constructor(private readonly packager: MacPackager, readonly outDir: string) {
@@ -31,11 +35,18 @@ export class PkgTarget extends Target {
3135
}
3236

3337
const appOutDir = this.outDir
34-
const distInfo = path.join(appOutDir, "distribution.xml")
35-
await exec("productbuild", ["--synthesize", "--component", appPath, this.installLocation, distInfo], {
38+
const distInfoFile = path.join(appOutDir, "distribution.xml")
39+
await exec("productbuild", ["--synthesize", "--component", appPath, this.installLocation, distInfoFile], {
3640
cwd: appOutDir,
3741
})
3842

43+
let distInfo = await readFile(distInfoFile, "utf-8")
44+
const insertIndex = distInfo.lastIndexOf("</installer-gui-script>")
45+
distInfo = distInfo.substring(0, insertIndex) + ` <domains enable_anywhere="${options.allowAnywhere}" enable_currentUserHome="${options.allowCurrentUserHome}" enable_localSystem="${options.allowRootDirectory}" />\n` + distInfo.substring(insertIndex)
46+
await writeFile(distInfoFile, distInfo)
47+
48+
debug(distInfo)
49+
3950
// to use --scripts, we must build .app bundle separately using pkgbuild
4051
// productbuild --scripts doesn't work (because scripts in this case not added to our package)
4152
// https://github.com/electron-userland/electron-osx-sign/issues/96#issuecomment-274986942
@@ -44,15 +55,15 @@ export class PkgTarget extends Target {
4455

4556
const outFile = path.join(appOutDir, packager.expandArtifactNamePattern(options, "pkg"))
4657
const args = prepareProductBuildArgs(identity, keychainName)
47-
args.push("--distribution", distInfo)
58+
args.push("--distribution", distInfoFile)
4859
args.push(outFile)
4960

5061
use(options.productbuild, it => args.push(...<any>it))
5162

5263
await exec("productbuild", args, {
5364
cwd: appOutDir,
5465
})
55-
await BluebirdPromise.all([unlink(innerPackageFile), unlink(distInfo)])
66+
await BluebirdPromise.all([unlink(innerPackageFile), unlink(distInfoFile)])
5667

5768
packager.dispatchArtifactCreated(outFile, this, arch, `${appInfo.name}-${appInfo.version}.pkg`)
5869
}

test/out/mac/__snapshots__/macArchiveTest.js.snap

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ Object {
7474
`;
7575

7676
exports[`pkg scripts 2`] = `
77+
Object {
78+
"mac": Array [
79+
Object {
80+
"arch": 1,
81+
"file": "Test App ßW-1.1.0.pkg",
82+
"safeArtifactName": "TestApp-1.1.0.pkg",
83+
},
84+
],
85+
}
86+
`;
87+
88+
exports[`pkg scripts 3`] = `
7789
Array [
7890
"Test App ßW.app",
7991
"Test App ßW.app/Contents",
@@ -399,7 +411,7 @@ Array [
399411
]
400412
`;
401413

402-
exports[`pkg scripts 3`] = `
414+
exports[`pkg scripts 4`] = `
403415
Object {
404416
"choice": Array [
405417
Object {
@@ -425,6 +437,11 @@ Object {
425437
},
426438
},
427439
},
440+
"domains": Object {
441+
"enable_anywhere": "true",
442+
"enable_currentUserHome": "true",
443+
"enable_localSystem": "true",
444+
},
428445
"minSpecVersion": "2",
429446
"options": Object {
430447
"customize": "never",

test/src/mac/macArchiveTest.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,20 @@ test("only zip", createMacTargetTest(["zip"]));
1515
test("tar.gz", createMacTargetTest(["tar.gz"]))
1616

1717
const it = process.env.CSC_KEY_PASSWORD == null ? test.skip : test.ifMac
18+
1819
it("pkg", createMacTargetTest(["pkg"]))
1920

21+
test.ifMac("pkg scripts", app({
22+
targets: Platform.MAC.createTarget("pkg"),
23+
config: {
24+
pkg: {
25+
installLocation: ""
26+
}
27+
}
28+
}, {
29+
signed: false,
30+
}))
31+
2032
test.ifMac("pkg scripts", app({
2133
targets: Platform.MAC.createTarget("pkg"),
2234
}, {

0 commit comments

Comments
 (0)