1
1
var path = require ( 'path' ) ;
2
2
var pkg = require ( path . resolve ( __dirname , '../package.json' ) ) ;
3
3
var fs = require ( 'fs' ) ;
4
- var cp = require ( 'child_process' ) ;
4
+ var run = require ( './run' ) ;
5
+ var format = require ( 'util' ) . format ;
6
+ var chalk = require ( 'chalk' ) ;
7
+ var figures = require ( 'figures' ) ;
5
8
var series = require ( 'run-series' ) ;
6
9
var _ = require ( 'lodash' ) ;
10
+ var packager = require ( 'electron-packager' ) ;
11
+ var createDMG = require ( 'electron-installer-dmg' ) ;
7
12
8
13
var debug = require ( 'debug' ) ( 'scout:tasks:darwin' ) ;
9
14
10
15
var NAME = pkg . product_name ;
11
16
var PACKAGE = path . join ( 'dist' , NAME + '-darwin-x64' ) ;
12
17
var APP_PATH = path . join ( PACKAGE , NAME + '.app' ) ;
13
18
14
- var packager = require ( 'electron-packager' ) ;
15
- var createDMG = require ( 'electron-installer-dmg' ) ;
16
-
17
19
module . exports . ELECTRON = path . join ( APP_PATH , 'Contents' , 'MacOS' , 'Electron' ) ;
18
20
module . exports . RESOURCES = path . join ( APP_PATH , 'Contents' , 'Resources' ) ;
19
21
@@ -29,7 +31,6 @@ var PACKAGER_CONFIG = {
29
31
prune : true ,
30
32
'app-bundle-id' : 'com.mongodb.compass' ,
31
33
'app-version' : pkg . version ,
32
- sign : '90E39AA7832E95369F0FC6DAF823A04DFBD9CF7A' ,
33
34
protocols : [
34
35
{
35
36
name : 'MongoDB Prototcol' ,
@@ -38,11 +39,6 @@ var PACKAGER_CONFIG = {
38
39
]
39
40
} ;
40
41
41
- // Adjust config via environment variables
42
- if ( process . env . SCOUT_INSTALLER_UNSIGNED !== undefined ) {
43
- PACKAGER_CONFIG . sign = null ;
44
- }
45
-
46
42
// @todo (imlucas): Standardize `electron-installer-dmg`
47
43
// options w/ `electron-installer-squirrel-windows`.
48
44
var INSTALLER_CONFIG = {
@@ -69,39 +65,127 @@ var INSTALLER_CONFIG = {
69
65
]
70
66
} ;
71
67
72
- module . exports . build = function ( done ) {
73
- fs . exists ( APP_PATH , function ( exists ) {
74
- if ( exists ) {
75
- debug ( '.app already exists. skipping packager run.' ) ;
76
- return done ( ) ;
68
+ var CODESIGN_IDENTITY_COMMON_NAME = 'Developer ID Application: Matt Kangas (ZD3CL9MT3L)' ;
69
+ var CODESIGN_IDENTITY_SHA1 = '90E39AA7832E95369F0FC6DAF823A04DFBD9CF7A' ;
70
+
71
+ /**
72
+ * Checks if the current environment can actually sign builds.
73
+ * If signing can be done, `electron-packager`'s config will
74
+ * be updated to sign artifacts. If not, gracefully degrade
75
+ *
76
+ * @param {Function } fn - Callback.
77
+ */
78
+ function addCodesignIdentityIfAvailable ( fn ) {
79
+ run ( 'certtool' , [ 'y' ] , function ( err , output ) {
80
+ if ( err ) {
81
+ debug ( 'Failed to list certificates. Build will not be signed.' ) ;
82
+ fn ( ) ;
83
+ return ;
77
84
}
78
- debug ( 'running packager to create electron binaries...' ) ;
79
- packager ( PACKAGER_CONFIG , done ) ;
85
+ if ( output . indexOf ( CODESIGN_IDENTITY_COMMON_NAME ) === - 1 ) {
86
+ debug ( 'Signing identity `%s` not detected. Build will not be signed.' ,
87
+ CODESIGN_IDENTITY_COMMON_NAME ) ;
88
+ fn ( ) ;
89
+ return ;
90
+ }
91
+
92
+ PACKAGER_CONFIG . sign = CODESIGN_IDENTITY_SHA1 ;
93
+ debug ( 'The signing identity `%s` is available! '
94
+ + 'This build will be signed!' , CODESIGN_IDENTITY_COMMON_NAME ) ;
95
+
96
+ console . log ( chalk . green . bold ( figures . tick ) ,
97
+ format ( ' This build will be signed using the `%s` signing identity' ,
98
+ CODESIGN_IDENTITY_COMMON_NAME ) ) ;
99
+ fn ( ) ;
80
100
} ) ;
81
- } ;
101
+ }
102
+
103
+ module . exports . build = function ( done ) {
104
+ addCodesignIdentityIfAvailable ( function ( err ) {
105
+ if ( err ) return done ( err ) ;
82
106
83
- var verify = function ( done ) {
84
- var cmd = 'codesign --verify "' + APP_PATH + '"' ;
85
- debug ( 'Verifying `%s` has been signed...' , APP_PATH ) ;
86
- cp . exec ( cmd , done ) ;
107
+ fs . exists ( APP_PATH , function ( exists ) {
108
+ if ( exists && process . env . NODE_ENV !== 'production' ) {
109
+ debug ( '.app already exists. skipping packager run.' ) ;
110
+ return done ( ) ;
111
+ }
112
+ debug ( 'running electron-packager...' ) ;
113
+ packager ( PACKAGER_CONFIG , done ) ;
114
+ } ) ;
115
+ } ) ;
87
116
} ;
88
117
89
- module . exports . installer = function ( done ) {
90
- debug ( 'creating installer...' ) ;
118
+ /**
119
+ * If the app is supposed to be signed, verify that
120
+ * the signing was actually completed correctly.
121
+ * If signing is not available, print helpful details
122
+ * on working with unsigned builds.
123
+ *
124
+ * @param {Function } done - Callback which receives `(err)`.
125
+ */
126
+ function verify ( done ) {
127
+ if ( ! PACKAGER_CONFIG . sign ) {
128
+ console . error ( chalk . yellow . bold ( figures . warning ) ,
129
+ ' User confusion ahead!' ) ;
91
130
92
- var tasks = [ ] ;
93
- if ( PACKAGER_CONFIG . sign ) {
94
- tasks . push ( verify ) ;
131
+ console . error ( chalk . gray (
132
+ ' The default preferences for OSX Gatekeeper will not' ,
133
+ 'allow users to run unsigned applications.' ) ) ;
134
+
135
+ console . error ( chalk . gray (
136
+ ' However, we\'re going to continue building' ,
137
+ 'the app and an installer because you\'re most likely' ) ) ;
138
+
139
+ console . error ( chalk . gray (
140
+ ' a developer trying to test' ,
141
+ 'the app\'s installation process.' ) ) ;
142
+
143
+ console . error ( chalk . gray (
144
+ ' For more information on OSX Gatekeeper and how to change your' ,
145
+ 'system preferences to run unsigned applications,' ) ) ;
146
+ console . error ( chalk . gray ( ' please see' ,
147
+ 'https://support.apple.com/en-us/HT202491' ) ) ;
148
+ debug ( 'Build is not signed. Skipping codesign verification.' ) ;
149
+ process . nextTick ( done ) ;
150
+ return ;
95
151
}
96
152
97
- tasks . push ( _ . partial ( createDMG , INSTALLER_CONFIG ) ) ;
153
+ debug ( 'Verifying `%s` has been signed correctly...' , APP_PATH ) ;
154
+ run ( 'codesign' , [ '--verify' , APP_PATH ] , function ( err ) {
155
+ if ( err ) {
156
+ err = new Error ( 'App is not correctly signed' ) ;
157
+ done ( err ) ;
158
+ return ;
159
+ }
160
+ debug ( 'Verified that the app has been signed correctly!' ) ;
161
+ done ( ) ;
162
+ } ) ;
163
+ }
164
+
165
+ /**
166
+ * Package the application as a single `.DMG` file which
167
+ * is the OSX equivalent of a `Setup.exe` installer.
168
+ *
169
+ * @param {Function } done - Callback which receives `(err)`.
170
+ */
171
+ module . exports . installer = function ( done ) {
172
+ debug ( 'creating installer...' ) ;
173
+
174
+ var tasks = [
175
+ verify ,
176
+ _ . partial ( createDMG , INSTALLER_CONFIG )
177
+ ] ;
98
178
99
179
series ( tasks , function ( err ) {
100
180
if ( err ) {
101
- console . error ( err . stack ) ;
181
+ console . error ( chalk . red . bold ( figures . cross ) ,
182
+ 'Failed to create DMG installer:' , err . message ) ;
183
+ console . error ( chalk . gray ( err . stack ) ) ;
102
184
return done ( err ) ;
103
185
}
104
- console . log ( 'Installer created!' ) ;
186
+ console . log ( chalk . green . bold ( figures . tick ) ,
187
+ ' DMG installer written to' ,
188
+ path . join ( INSTALLER_CONFIG . out , INSTALLER_CONFIG . name + '.dmg' ) ) ;
105
189
done ( ) ;
106
190
} ) ;
107
191
} ;
0 commit comments