@vscode/gulp-electron 1.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ **Deprecated**
2
+
3
+ Please use the official way of requiring Electron: https://electronjs.org/docs/tutorial/first-app
4
+
5
+ --
6
+
7
+ # @vscode/gulp-electron
8
+
9
+ ### Installation
10
+
11
+ ```bash
12
+ npm install --save-dev @vscode/gulp-electron
13
+ ```
14
+
15
+ ### Usage
16
+
17
+ You can use this module in two distinct ways: **to package your application** and/or
18
+ **to download a version of Electron** to disk.
19
+
20
+ #### How to Package Your Application
21
+
22
+ You should source your app's files using `gulp.src` and pipe them through
23
+ `@vscode/gulp-electron`. The following task will create your application in
24
+ the `app` folder, ready for launch.
25
+
26
+ ```javascript
27
+ var gulp = require("gulp");
28
+ var symdest = require("gulp-symdest");
29
+ var electron = require("@vscode/gulp-electron");
30
+
31
+ gulp.task("default", function () {
32
+ return gulp
33
+ .src("src/**")
34
+ .pipe(electron({ version: "0.34.1", platform: "darwin" }))
35
+ .pipe(symdest("app"));
36
+ });
37
+ ```
38
+
39
+ **Note:** It is important to use `gulp-symdest` only because of the OS X
40
+ platform. An application bundle has symlinks within and if you use `gulp.dest`
41
+ to pipe the built app to disk, those will be missing. `symdest` will make
42
+ sure symlinks are taken into account.
43
+
44
+ Finally, you can always pipe it to a **zip archive** for easy distribution.
45
+ [joaomoreno/gulp-vinyl-zip](https://github.com/joaomoreno/gulp-vinyl-zip) is recommended:
46
+
47
+ ```javascript
48
+ var gulp = require("gulp");
49
+ var zip = require("gulp-vinyl-zip");
50
+ var electron = require("@vscode/gulp-electron");
51
+
52
+ gulp.task("default", function () {
53
+ return gulp
54
+ .src("src/**")
55
+ .pipe(electron({ version: "0.34.1", platform: "darwin" }))
56
+ .pipe(zip.dest("app-darwin.zip"));
57
+ });
58
+ ```
59
+
60
+ #### How to Download Electron
61
+
62
+ There's also a very handy export `electron.dest()` function that
63
+ makes sure you always have the exact version of Electron in a directory:
64
+
65
+ ```javascript
66
+ var gulp = require("gulp");
67
+ var electron = require("@vscode/gulp-electron");
68
+
69
+ gulp.task("default", function () {
70
+ return electron.dest("electron-build", {
71
+ version: "0.34.1",
72
+ platform: "darwin",
73
+ });
74
+ });
75
+ ```
76
+
77
+ This will place a vanilla Electron build into the `electron-build` directory.
78
+ If you run it consecutively and it detects that the version in the destination directory
79
+ is the intended one, it will end up in a no-op. Else it will download the provided version
80
+ and replace it.
81
+
82
+ ### Options
83
+
84
+ You **must** provide the following options:
85
+
86
+ - `version` - the [Electron version](https://github.com/atom/electron/releases) to use
87
+ - `platform` - kind of OS (`darwin`, `linux`, `win32`)
88
+
89
+ The following options are **optional**:
90
+
91
+ - `quiet` - suppress a progress bar when downloading
92
+ - `token` - GitHub access token(to avoid request limit. You can grab it [here](https://github.com/settings/tokens))
93
+
94
+ - `arch` - the processor architecture (`ia32`, `x64`)
95
+
96
+ - **Windows**
97
+
98
+ - `winIcon` - path to an `.ico` file
99
+ - `companyName` - company name
100
+ - `copyright` - copyright statement
101
+
102
+ - **Darwin**
103
+
104
+ - `darwinIcon` - path to an `.icns` file
105
+ - `darwinHelpBookFolder` - the `CFBundleHelpBookFolder` value
106
+ - `darwinHelpBookName` - the `CFBundleHelpBookName` value
107
+ - `darwinBundleDocumentTypes` - ([reference](https://developer.apple.com/library/ios/documentation/filemanagement/conceptual/documentinteraction_topicsforios/Articles/RegisteringtheFileTypesYourAppSupports.html)) array of dictionaries, each containing the following structure:
108
+ - `name` - the `CFBundleTypeName` value
109
+ - `role` - the `CFBundleTypeRole` value
110
+ - `ostypes` - the `CFBundleTypeOSTypes` value, a `string` array
111
+ - `utis` - the `LSItemContentTypes` value, a `string` array
112
+ - `extensions` - the `CFBundleTypeExtensions` value, a `string` array of file extensions
113
+ - `iconFile` - the `CFBundleTypeIconFile` value
114
+ - `darwinForceDarkModeSupport` - Forces Mojave dark mode support to be enabled for older Electron versions
115
+
116
+ - **Linux**
117
+ - `linuxExecutableName` - overwrite the name of the executable in Linux
@@ -0,0 +1,40 @@
1
+ trigger:
2
+ batch: true
3
+ branches:
4
+ include:
5
+ - main
6
+
7
+ pr: [main]
8
+
9
+ resources:
10
+ repositories:
11
+ - repository: templates
12
+ type: github
13
+ name: microsoft/vscode-engineering
14
+ ref: main
15
+ endpoint: Monaco
16
+
17
+ parameters:
18
+ - name: publishPackage
19
+ displayName: 🚀 Publish
20
+ type: boolean
21
+ default: false
22
+
23
+ extends:
24
+ template: azure-pipelines/npm-package/pipeline.yml@templates
25
+ parameters:
26
+ npmPackages:
27
+ - name: gulp-electron
28
+ buildSteps:
29
+ - script: npm ci
30
+ testPlatforms:
31
+ - name: Linux
32
+ nodeVersions: [14.x, 16.x, 17.x]
33
+ - name: MacOS
34
+ nodeVersions: [14.x, 16.x, 17.x]
35
+ - name: Windows
36
+ nodeVersions: [14.x, 16.x, 17.x]
37
+ testSteps:
38
+ - script: npm ci
39
+ - script: npm test
40
+ publishPackage: ${{ parameters.publishPackage }}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@vscode/gulp-electron",
3
+ "version": "1.33.0",
4
+ "description": "gulp plugin for packaging Electron into VS Code",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "mocha"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/microsoft/vscode-gulp-electron.git"
12
+ },
13
+ "engines": {
14
+ "node": ">=10"
15
+ },
16
+ "keywords": [
17
+ "gulpplugin",
18
+ "atom",
19
+ "shell",
20
+ "atom-shell",
21
+ "electron",
22
+ "github"
23
+ ],
24
+ "author": "João Moreno",
25
+ "license": "MIT",
26
+ "bugs": {
27
+ "url": "https://github.com/microsoft/vscode-gulp-electron/issues"
28
+ },
29
+ "homepage": "https://github.com/microsoft/vscode-gulp-electron",
30
+ "dependencies": {
31
+ "@electron/get": "^2.0.2",
32
+ "@octokit/rest": "^18.0.14",
33
+ "event-stream": "3.3.4",
34
+ "gulp-filter": "^5.1.0",
35
+ "gulp-rename": "1.2.2",
36
+ "gulp-symdest": "^1.2.0",
37
+ "gulp-vinyl-zip": "^2.1.2",
38
+ "mkdirp": "^0.5.1",
39
+ "plist": "^3.0.1",
40
+ "progress": "^1.1.8",
41
+ "rcedit": "^0.3.0",
42
+ "rimraf": "^2.4.2",
43
+ "semver": "^4.3.4",
44
+ "temp": "^0.8.3",
45
+ "vinyl": "^2.2.0",
46
+ "vinyl-fs": "^3.0.3"
47
+ },
48
+ "devDependencies": {
49
+ "gulp-buffer": "0.0.2",
50
+ "mocha": "^9.2.2"
51
+ }
52
+ }
package/src/darwin.js ADDED
@@ -0,0 +1,410 @@
1
+ "use strict";
2
+
3
+ var path = require("path");
4
+ var plist = require("plist");
5
+ var es = require("event-stream");
6
+ var vfs = require("vinyl-fs");
7
+ var File = require("vinyl");
8
+ var rename = require("gulp-rename");
9
+ var semver = require("semver");
10
+
11
+ function getOriginalAppName(opts) {
12
+ return semver.gte(opts.version, "0.24.0") ? "Electron" : "Atom";
13
+ }
14
+
15
+ function getOriginalAppFullName(opts) {
16
+ return getOriginalAppName(opts) + ".app";
17
+ }
18
+
19
+ function getAppName(opts) {
20
+ return (opts.productAppName || opts.productName) + ".app";
21
+ }
22
+
23
+ exports.getAppPath = function (opts) {
24
+ return getAppName(opts) + "/Contents/Resources/app";
25
+ };
26
+
27
+ function removeDefaultApp(opts) {
28
+ var defaultAppPath = path.join(
29
+ getOriginalAppFullName(opts),
30
+ "Contents",
31
+ "Resources",
32
+ "default_app"
33
+ );
34
+
35
+ return es.mapSync(function (f) {
36
+ if (!f.relative.startsWith(defaultAppPath)) {
37
+ return f;
38
+ }
39
+ });
40
+ }
41
+
42
+ function patchIcon(opts) {
43
+ if (!opts.darwinIcon) {
44
+ return es.through();
45
+ }
46
+
47
+ var resourcesPath = path.join(
48
+ getOriginalAppFullName(opts),
49
+ "Contents",
50
+ "Resources"
51
+ );
52
+ var iconName = semver.gte(opts.version, "0.24.0")
53
+ ? "electron.icns"
54
+ : "atom.icns";
55
+ var originalIconPath = path.join(resourcesPath, iconName);
56
+ var iconPath = path.join(resourcesPath, opts.productName + ".icns");
57
+ var pass = es.through();
58
+
59
+ // filter out original icon
60
+ var src = pass.pipe(
61
+ es.mapSync(function (f) {
62
+ if (f.relative !== originalIconPath) {
63
+ return f;
64
+ }
65
+ })
66
+ );
67
+
68
+ // add custom icon
69
+ var icon = vfs.src(opts.darwinIcon).pipe(rename(iconPath));
70
+
71
+ return es.duplex(pass, es.merge(src, icon));
72
+ }
73
+
74
+ function patchInfoPlist(opts) {
75
+ var contentsPath = path.join(getOriginalAppFullName(opts), "Contents");
76
+ var resourcesPath = path.join(contentsPath, "Resources");
77
+ var infoPlistPath = path.join(contentsPath, "Info.plist");
78
+ var didCloseIcons = false;
79
+
80
+ var icons = es.through();
81
+ var input = es.through();
82
+ var output = input.pipe(
83
+ es.map(function (f, cb) {
84
+ if (f.relative !== infoPlistPath) {
85
+ return cb(null, f);
86
+ }
87
+
88
+ var contents = "";
89
+
90
+ f.contents.on("error", function (err) {
91
+ cb(err);
92
+ });
93
+
94
+ f.contents.on("data", function (d) {
95
+ contents += d;
96
+ });
97
+
98
+ f.contents.on("end", function () {
99
+ var infoPlist = plist.parse(contents.toString("utf8"));
100
+
101
+ opts.darwinBundleIdentifier &&
102
+ (infoPlist["CFBundleIdentifier"] = opts.darwinBundleIdentifier);
103
+ opts.darwinApplicationCategoryType &&
104
+ (infoPlist["LSApplicationCategoryType"] =
105
+ opts.darwinApplicationCategoryType);
106
+ infoPlist["CFBundleName"] = opts.productName;
107
+ infoPlist["CFBundleDisplayName"] =
108
+ opts.productDisplayName || opts.productName;
109
+ infoPlist["CFBundleVersion"] = opts.productVersion;
110
+ infoPlist["CFBundleShortVersionString"] = opts.productVersion;
111
+ opts.copyright &&
112
+ (infoPlist["NSHumanReadableCopyright"] = opts.copyright);
113
+ infoPlist["CFBundleIconFile"] = opts.productName + ".icns";
114
+
115
+ if (opts.darwinExecutable) {
116
+ infoPlist["CFBundleExecutable"] = opts.darwinExecutable;
117
+ }
118
+
119
+ //Register the Application Help Book if it exists
120
+ if (opts.darwinHelpBookFolder && opts.darwinHelpBookName) {
121
+ infoPlist["CFBundleHelpBookFolder"] = opts.darwinHelpBookFolder;
122
+ infoPlist["CFBundleHelpBookName"] = opts.darwinHelpBookName;
123
+ }
124
+
125
+ if (opts.darwinBundleDocumentTypes) {
126
+ var iconsPaths = [];
127
+
128
+ infoPlist["CFBundleDocumentTypes"] = (
129
+ infoPlist["CFBundleDocumentTypes"] || []
130
+ ).concat(
131
+ opts.darwinBundleDocumentTypes.map(function (type) {
132
+ iconsPaths.push(type.iconFile);
133
+
134
+ var result = {
135
+ CFBundleTypeName: type.name,
136
+ CFBundleTypeRole: type.role,
137
+ CFBundleTypeOSTypes: type.ostypes,
138
+ CFBundleTypeExtensions: type.extensions,
139
+ CFBundleTypeIconFile: path.basename(type.iconFile),
140
+ };
141
+
142
+ if (type.utis) {
143
+ result["LSItemContentTypes"] = type.utis;
144
+ }
145
+
146
+ return result;
147
+ })
148
+ );
149
+
150
+ if (iconsPaths.length) {
151
+ didCloseIcons = true;
152
+ es.merge(
153
+ iconsPaths.map(function (iconPath) {
154
+ return vfs.src(iconPath).pipe(
155
+ rename(function (path) {
156
+ path.dirname = resourcesPath;
157
+ })
158
+ );
159
+ })
160
+ ).pipe(icons);
161
+ }
162
+ }
163
+
164
+ if (opts.darwinBundleURLTypes) {
165
+ infoPlist["CFBundleURLTypes"] = opts.darwinBundleURLTypes.map(
166
+ function (type) {
167
+ return {
168
+ CFBundleTypeRole: type.role,
169
+ CFBundleURLName: type.name,
170
+ CFBundleURLSchemes: type.urlSchemes,
171
+ };
172
+ }
173
+ );
174
+ }
175
+
176
+ if (opts.darwinForceDarkModeSupport) {
177
+ infoPlist["NSRequiresAquaSystemAppearance"] = false;
178
+ }
179
+
180
+ f.contents = Buffer.from(plist.build(infoPlist), "utf8");
181
+ cb(null, f);
182
+ });
183
+ }))
184
+ .pipe(
185
+ es.through(
186
+ null,
187
+ function () {
188
+ if (!didCloseIcons) {
189
+ es.readArray([]).pipe(icons);
190
+ }
191
+
192
+ this.emit("end");
193
+ }
194
+ )
195
+ );
196
+
197
+ return es.duplex(input, es.merge(output, icons));
198
+ }
199
+
200
+ function createEntitlementsPlist(opts) {
201
+ var input = es.through();
202
+ if (!opts.darwinEntitlements) {
203
+ return input;
204
+ }
205
+
206
+ var contentsPath = path.join(getOriginalAppFullName(opts), "Contents");
207
+ var entitlementsPlistPath = path.join(contentsPath, "Entitlements.plist");
208
+
209
+ var result = {};
210
+ opts.darwinEntitlements.forEach((element) => {
211
+ result[element] = true;
212
+ });
213
+
214
+ var entitlementsFile = new File({
215
+ path: entitlementsPlistPath,
216
+ contents: Buffer.from(plist.build(result)),
217
+ });
218
+
219
+ return es.duplex(input, es.merge(input, es.readArray([entitlementsFile])));
220
+ }
221
+
222
+ function patchHelperInfoPlist(opts) {
223
+ var didCloseIcons = false;
224
+
225
+ var icons = es.through();
226
+ var input = es.through();
227
+ var output = input.pipe(
228
+ es.map(function (f, cb) {
229
+ if (
230
+ !/Contents\/Frameworks\/Electron\ Helper( \w+)?\.app\/Contents\/Info.plist$/i.test(
231
+ f.relative
232
+ )
233
+ ) {
234
+ return cb(null, f);
235
+ }
236
+
237
+ var contents = "";
238
+
239
+ f.contents.on("error", function (err) {
240
+ cb(err);
241
+ });
242
+
243
+ f.contents.on("data", function (d) {
244
+ contents += d;
245
+ });
246
+
247
+ f.contents.on("end", function () {
248
+ var infoPlist = plist.parse(contents.toString("utf8"));
249
+ var match = /\.helper\.([^.]+)$/.exec(
250
+ infoPlist["CFBundleIdentifier"] || ""
251
+ );
252
+ var suffix = match ? match[1] : "";
253
+
254
+ if (opts.darwinBundleIdentifier) {
255
+ infoPlist["CFBundleIdentifier"] =
256
+ opts.darwinBundleIdentifier + ".helper";
257
+
258
+ if (suffix) {
259
+ infoPlist["CFBundleIdentifier"] += "." + suffix;
260
+ }
261
+ }
262
+
263
+ infoPlist["CFBundleName"] = opts.productName + " Helper";
264
+ if (suffix) {
265
+ infoPlist["CFBundleName"] += " " + suffix;
266
+ }
267
+
268
+ if (infoPlist["CFBundleDisplayName"]) {
269
+ infoPlist["CFBundleDisplayName"] = infoPlist["CFBundleName"];
270
+ }
271
+
272
+ if (infoPlist["CFBundleExecutable"]) {
273
+ infoPlist["CFBundleExecutable"] = infoPlist["CFBundleName"];
274
+ }
275
+
276
+ f.contents = Buffer.from(plist.build(infoPlist), "utf8");
277
+ cb(null, f);
278
+ });
279
+ }))
280
+ .pipe(
281
+ es.through(
282
+ null,
283
+ function () {
284
+ if (!didCloseIcons) {
285
+ es.readArray([]).pipe(icons);
286
+ }
287
+
288
+ this.emit("end");
289
+ }
290
+ )
291
+ );
292
+
293
+ return es.duplex(input, es.merge(output, icons));
294
+ }
295
+
296
+ function addCredits(opts) {
297
+ if (!opts.darwinCredits) {
298
+ return es.through();
299
+ }
300
+
301
+ var creditsPath = path.join(
302
+ getOriginalAppFullName(opts),
303
+ "Contents",
304
+ "Resources",
305
+ "Credits.rtf"
306
+ );
307
+ var input = es.through();
308
+ var credits;
309
+
310
+ if (typeof opts.darwinCredits === "string") {
311
+ credits = vfs.src(opts.darwinCredits).pipe(rename(creditsPath));
312
+ } else if (opts.darwinCredits instanceof Buffer) {
313
+ credits = es.readArray([
314
+ new File({
315
+ path: creditsPath,
316
+ contents: opts.darwinCredits,
317
+ }),
318
+ ]);
319
+ } else {
320
+ throw new Error("Unexpected value for darwinCredits");
321
+ }
322
+
323
+ return es.duplex(input, es.merge(input, credits));
324
+ }
325
+
326
+ function renameApp(opts) {
327
+ var originalAppName = getOriginalAppName(opts);
328
+ var originalAppNameRegexp = new RegExp("^" + getOriginalAppFullName(opts));
329
+ var appName = getAppName(opts);
330
+
331
+ return rename(function (path) {
332
+ // The app folder itself looks like a file
333
+ if (
334
+ path.dirname === "." &&
335
+ path.basename === originalAppName &&
336
+ path.extname === ".app"
337
+ ) {
338
+ path.basename = opts.productAppName || opts.productName;
339
+ } else {
340
+ path.dirname = path.dirname.replace(originalAppNameRegexp, appName);
341
+ }
342
+
343
+ if (
344
+ /Contents\/MacOS$/.test(path.dirname) &&
345
+ path.basename === "Electron" &&
346
+ opts.darwinExecutable
347
+ ) {
348
+ path.basename = opts.darwinExecutable;
349
+ }
350
+ });
351
+ }
352
+
353
+ function renameAppHelper(opts) {
354
+ var originalAppName = getOriginalAppName(opts);
355
+ var originalAppNameRegexp = new RegExp("^" + getOriginalAppFullName(opts));
356
+ var appName = getAppName(opts);
357
+ var name = opts.productName;
358
+
359
+ return rename(function (path) {
360
+ var basenameMatch = /^Electron Helper( \(\w+\))?$/.exec(path.basename);
361
+
362
+ if (
363
+ /Contents\/Frameworks/.test(path.dirname) &&
364
+ path.extname === ".app" &&
365
+ basenameMatch
366
+ ) {
367
+ var suffix = basenameMatch[1] || "";
368
+ path.basename = name + " Helper" + suffix;
369
+ } else if (
370
+ /Contents\/Frameworks\/Electron\ Helper( \(\w+\))?\.app/.test(
371
+ path.dirname
372
+ )
373
+ ) {
374
+ var isInMacOS = /Contents\/Frameworks\/Electron\ Helper( \(\w+\))?\.app\/Contents\/MacOS$/.test(
375
+ path.dirname
376
+ );
377
+ path.dirname = path.dirname.replace(
378
+ /Electron\ Helper( \(\w+\))?\.app/,
379
+ name + " Helper$1.app"
380
+ );
381
+
382
+ if (
383
+ isInMacOS &&
384
+ /^Electron Helper( \(\w+\))?$/.test(path.basename) &&
385
+ path.extname === ""
386
+ ) {
387
+ path.basename = path.basename.replace(
388
+ /Electron\ Helper( \(\w+\))?$/,
389
+ name + " Helper$1"
390
+ );
391
+ }
392
+ }
393
+ });
394
+ }
395
+
396
+ exports.patch = function (opts) {
397
+ var pass = es.through();
398
+
399
+ var src = pass
400
+ .pipe(opts.keepDefaultApp ? es.through() : removeDefaultApp(opts))
401
+ .pipe(patchIcon(opts))
402
+ .pipe(patchInfoPlist(opts))
403
+ .pipe(patchHelperInfoPlist(opts))
404
+ .pipe(createEntitlementsPlist(opts))
405
+ .pipe(addCredits(opts))
406
+ .pipe(renameApp(opts))
407
+ .pipe(renameAppHelper(opts));
408
+
409
+ return es.duplex(pass, src);
410
+ };
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+
3
+ var path = require("path");
4
+ const { downloadArtifact } = require("@electron/get");
5
+ const ProgressBar = require("progress");
6
+ var rename = require("gulp-rename");
7
+ var es = require("event-stream");
8
+ var zfs = require("gulp-vinyl-zip");
9
+ var filter = require("gulp-filter");
10
+ const { Octokit } = require("@octokit/rest");
11
+ const got = require("got");
12
+
13
+ async function getDownloadUrl(
14
+ ownerRepo,
15
+ { version, platform, arch, token, artifactName, artifactSuffix }
16
+ ) {
17
+ const [owner, repo] = ownerRepo.split("/");
18
+ const octokit = new Octokit({ auth: token });
19
+ const releaseVersion = version.startsWith("v") ? version : `v${version}`;
20
+
21
+ const { data: release } = await octokit.repos.getReleaseByTag({
22
+ owner,
23
+ repo,
24
+ tag: releaseVersion,
25
+ });
26
+
27
+ if (!release) {
28
+ throw new Error(`Release for ${releaseVersion} not found`);
29
+ }
30
+
31
+ const { data: assets } = await octokit.repos.listReleaseAssets({
32
+ owner,
33
+ repo,
34
+ release_id: release.id,
35
+ });
36
+
37
+ artifactName = artifactName || "electron";
38
+
39
+ const targetName = artifactSuffix ?
40
+ `${artifactName}-${releaseVersion}-${platform}-${arch}-${artifactSuffix}.zip` :
41
+ `${artifactName}-${releaseVersion}-${platform}-${arch}.zip`;
42
+ const asset = assets.find((asset) => {
43
+ return asset.name === targetName;
44
+ });
45
+
46
+ if (!asset) {
47
+ throw new Error(`Release asset for ${releaseVersion} not found`);
48
+ }
49
+
50
+ const requestOptions = await octokit.repos.getReleaseAsset.endpoint({
51
+ owner,
52
+ repo,
53
+ asset_id: asset.id,
54
+ headers: {
55
+ Accept: "application/octet-stream",
56
+ },
57
+ });
58
+
59
+ const { url, headers } = requestOptions;
60
+ headers.authorization = `token ${token}`;
61
+
62
+ const response = await got(url, {
63
+ followRedirect: false,
64
+ method: "HEAD",
65
+ headers,
66
+ });
67
+
68
+ return response.headers.location;
69
+ }
70
+
71
+ async function download(opts) {
72
+ let bar;
73
+
74
+ if (!opts.version) {
75
+ throw new Error("Missing version");
76
+ }
77
+
78
+ if (!opts.platform) {
79
+ throw new Error("Missing platform");
80
+ }
81
+
82
+ let arch = opts.arch;
83
+ if (!arch) {
84
+ switch (opts.platform) {
85
+ case "darwin":
86
+ arch = "x64";
87
+ break;
88
+ case "win32":
89
+ arch = "ia32";
90
+ break;
91
+ case "linux":
92
+ arch = "ia32";
93
+ break;
94
+ }
95
+ }
96
+
97
+ let downloadOpts = {
98
+ version: opts.version,
99
+ platform: opts.platform,
100
+ arch,
101
+ artifactName: opts.artifactName,
102
+ artifactSuffix: opts.artifactSuffix,
103
+ token: opts.token,
104
+ downloadOptions: {
105
+ getProgressCallback: (progress) => {
106
+ if (bar) bar.update(progress.percent);
107
+ },
108
+ },
109
+ };
110
+
111
+ bar = new ProgressBar(
112
+ `Downloading ${opts.artifactName}: [:bar] :percent ETA: :eta seconds `,
113
+ {
114
+ curr: 0,
115
+ total: 100,
116
+ }
117
+ );
118
+
119
+ if (opts.repo) {
120
+ const url = await getDownloadUrl(opts.repo, downloadOpts);
121
+
122
+ downloadOpts = {
123
+ ...downloadOpts,
124
+ mirrorOptions: {
125
+ mirror: `https://github.com/${opts.repo}/releases/download/`,
126
+ resolveAssetURL: () => url,
127
+ },
128
+ unsafelyDisableChecksums: true,
129
+ };
130
+ }
131
+
132
+ const start = new Date();
133
+ bar.start = start;
134
+
135
+ return await downloadArtifact(downloadOpts);
136
+ }
137
+
138
+ function downloadStream(opts) {
139
+ return es.readable(function (_, cb) {
140
+ download(opts).then(
141
+ (assets) => {
142
+ zfs
143
+ .src(assets)
144
+ .on("data", (data) => this.emit("data", data))
145
+ .on("error", (err) => this.emit("error", err))
146
+ .on("end", () => this.emit("end"));
147
+ },
148
+ (err) => cb(err)
149
+ );
150
+ });
151
+ }
152
+
153
+ function getDarwinLibFFMpegPath(opts) {
154
+ return path.join(
155
+ "Electron.app",
156
+ "Contents",
157
+ "Frameworks",
158
+ "Electron Framework.framework",
159
+ "Versions",
160
+ "A",
161
+ "Libraries",
162
+ "libffmpeg.dylib"
163
+ );
164
+ }
165
+
166
+ module.exports = function (opts) {
167
+ const downloadOpts = {
168
+ version: opts.version,
169
+ platform: opts.platform,
170
+ arch: opts.arch === "arm" ? "armv7l" : opts.arch,
171
+ artifactName: "electron",
172
+ token: opts.token,
173
+ quiet: opts.quiet,
174
+ repo: opts.repo,
175
+ symbols: opts.symbols,
176
+ pdbs: opts.pdbs,
177
+ };
178
+
179
+ if (opts.symbols) {
180
+ return downloadStream({ ...downloadOpts, artifactSuffix: "symbols" });
181
+ } else if (opts.pdbs) {
182
+ return downloadStream({ ...downloadOpts, artifactSuffix: "pdb" });
183
+ } else {
184
+ let electron = downloadStream(downloadOpts);
185
+
186
+ if (!opts.ffmpegChromium) {
187
+ return electron;
188
+ }
189
+
190
+ electron = electron.pipe(filter(["**", "!**/*ffmpeg.*"]));
191
+
192
+ let ffmpeg = downloadStream({
193
+ ...downloadOpts,
194
+ artifactName: "ffmpeg",
195
+ }).pipe(filter("**/*ffmpeg.*"));
196
+
197
+ if (opts.platform === "darwin") {
198
+ ffmpeg = ffmpeg.pipe(rename(getDarwinLibFFMpegPath(opts)));
199
+ }
200
+
201
+ return es.merge(electron, ffmpeg);
202
+ }
203
+ };
204
+
205
+ module.exports.download = download;
package/src/index.js ADDED
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ var path = require("path");
4
+ var es = require("event-stream");
5
+ var fs = require("fs");
6
+ var rename = require("gulp-rename");
7
+ var rimraf = require("rimraf");
8
+ var symdest = require("gulp-symdest");
9
+ var download = require("./download");
10
+ var semver = require("semver");
11
+
12
+ function moveApp(platform, opts) {
13
+ var appPath = platform.getAppPath(opts);
14
+
15
+ return rename(function (path) {
16
+ path.dirname = appPath + (path.dirname === "." ? "" : "/" + path.dirname);
17
+ });
18
+ }
19
+
20
+ function _electron(opts) {
21
+ var pass = es.through();
22
+ var result = es.through();
23
+
24
+ var buffer = [];
25
+
26
+ var src = pass.pipe(
27
+ es.through(function (f) {
28
+ if (!buffer) {
29
+ return;
30
+ }
31
+
32
+ buffer.push(f);
33
+
34
+ if (f.relative !== "package.json") {
35
+ return;
36
+ }
37
+
38
+ var json = JSON.parse(f.contents.toString("utf8"));
39
+ opts = { ...opts };
40
+
41
+ // We need to extract the application's name and version
42
+ // in order to feed it to the various platforms build
43
+ // process.
44
+ opts.productName = json.name;
45
+ opts.productVersion = json.version;
46
+
47
+ var platform = require("./" + opts.platform);
48
+
49
+ var sources = es
50
+ .merge(es.readArray(buffer), pass)
51
+ .pipe(moveApp(platform, opts));
52
+
53
+ var electron = download(opts).pipe(platform.patch(opts));
54
+
55
+ es.merge(sources, electron).pipe(result);
56
+
57
+ buffer = null;
58
+ })
59
+ );
60
+
61
+ return es.duplex(pass, es.merge(src, result));
62
+ }
63
+
64
+ function electron(opts) {
65
+ if (!opts.version) {
66
+ throw new Error("Missing Electron option: version.");
67
+ }
68
+
69
+ if (!opts.platform) {
70
+ throw new Error("Missing Electron option: platform.");
71
+ }
72
+
73
+ if (opts.ffmpegChromium && !semver.gte(opts.version, "0.36.7")) {
74
+ throw new Error(
75
+ "ffmpegChromium option is only supported in Electron versions >= v0.36.8."
76
+ );
77
+ }
78
+
79
+ if (opts.productName) {
80
+ console.warn(
81
+ "productName is deprecated. The application's name will be picked up automatically from package.json."
82
+ );
83
+ }
84
+
85
+ if (opts.productVersion) {
86
+ console.warn(
87
+ "productVersion is deprecated. The application's version will be picked up automatically from package.json."
88
+ );
89
+ }
90
+
91
+ return _electron(opts);
92
+ }
93
+
94
+ function dest(destination, opts) {
95
+ if (!destination) {
96
+ throw new Error("Missing destination.");
97
+ }
98
+
99
+ opts = opts || {};
100
+ opts.platform = opts.platform || process.platform;
101
+ opts.arch = opts.arch || process.arch;
102
+
103
+ var shouldUpdate = false;
104
+
105
+ try {
106
+ var version = fs.readFileSync(path.join(destination, "version"), "utf8");
107
+ shouldUpdate = version !== "v" + opts.version;
108
+ } catch (e) {
109
+ shouldUpdate = true;
110
+ }
111
+
112
+ if (!shouldUpdate) {
113
+ return;
114
+ }
115
+
116
+ var result = es.through();
117
+
118
+ rimraf(destination, function (err) {
119
+ if (err) {
120
+ return result.emit("error", err);
121
+ }
122
+
123
+ var stream = download(opts);
124
+
125
+ if (opts.platform === "win32" && opts.win32ExeBasename) {
126
+ stream = stream.pipe(
127
+ rename(function (path) {
128
+ if (
129
+ path.dirname === "." &&
130
+ path.basename === "electron" &&
131
+ path.extname === ".exe"
132
+ ) {
133
+ path.basename = opts.win32ExeBasename;
134
+ }
135
+ })
136
+ );
137
+ }
138
+
139
+ stream.pipe(symdest(destination)).pipe(result);
140
+ });
141
+
142
+ return result;
143
+ }
144
+
145
+ electron.dest = dest;
146
+ module.exports = electron;
package/src/linux.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ var path = require("path");
4
+ var es = require("event-stream");
5
+ var rename = require("gulp-rename");
6
+ var semver = require("semver");
7
+
8
+ function getOriginalAppName(opts) {
9
+ return semver.gte(opts.version, "0.24.0") ? "electron" : "atom";
10
+ }
11
+
12
+ exports.getAppPath = function (opts) {
13
+ return "resources/app";
14
+ };
15
+
16
+ function removeDefaultApp() {
17
+ var defaultAppPath = path.join("resources", "default_app");
18
+
19
+ return es.mapSync(function (f) {
20
+ if (!f.relative.startsWith(defaultAppPath)) {
21
+ return f;
22
+ }
23
+ });
24
+ }
25
+
26
+ function renameApp(opts) {
27
+ return rename(function (path) {
28
+ if (
29
+ path.dirname === "." &&
30
+ path.basename === getOriginalAppName(opts) &&
31
+ path.extname === ""
32
+ ) {
33
+ path.basename = opts.linuxExecutableName || opts.productName;
34
+ }
35
+ });
36
+ }
37
+
38
+ /**
39
+ * For Electron versions that support the setuid sandbox on Linux, changes the permissions of
40
+ * the `chrome-sandbox` executable as appropriate.
41
+ *
42
+ * The sandbox helper executable must have the setuid (`+s` / `0o4000`) bit set.
43
+ *
44
+ * See: https://github.com/electron/electron/pull/17269#issuecomment-470671914
45
+ */
46
+ function updateSandboxHelperPermissions() {
47
+ return es.mapSync(function (f) {
48
+ if (!f.isNull() && !f.isDirectory() && f.path === "chrome-sandbox") {
49
+ f.stat.mode = 0o4755;
50
+ }
51
+ return f;
52
+ });
53
+ }
54
+
55
+ exports.patch = function (opts) {
56
+ var pass = es.through();
57
+
58
+ var src = pass
59
+ .pipe(updateSandboxHelperPermissions())
60
+ .pipe(opts.keepDefaultApp ? es.through() : removeDefaultApp())
61
+ .pipe(renameApp(opts));
62
+
63
+ return es.duplex(pass, src);
64
+ };
package/src/win32.js ADDED
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+
3
+ var fs = require("fs");
4
+ var path = require("path");
5
+ var es = require("event-stream");
6
+ var rename = require("gulp-rename");
7
+ var temp = require("temp").track();
8
+ var rcedit = require("rcedit");
9
+ var semver = require("semver");
10
+ var { spawnSync } = require("child_process");
11
+
12
+ function getOriginalAppName(opts) {
13
+ return semver.gte(opts.version, "0.24.0") ? "electron" : "atom";
14
+ }
15
+
16
+ function getOriginalAppFullName(opts) {
17
+ return getOriginalAppName(opts) + ".exe";
18
+ }
19
+
20
+ function getSignTool() {
21
+ let windowsSDKDir= "C:\\Program Files (x86)\\Windows Kits\\10\\bin\\";
22
+ if (!fs.existsSync(windowsSDKDir)) {
23
+ throw `There is no Windows 10 SDK installed at ${windowsSDKDir}.`;
24
+ }
25
+
26
+ let findSignTool = (start) => {
27
+ let signToolPaths = [];
28
+ fs.readdirSync(start).forEach(file => {
29
+ const filename = path.join(start, file);
30
+ const stat = fs.lstatSync(filename);
31
+ if (stat.isDirectory()) {
32
+ signToolPaths = signToolPaths.concat(findSignTool(filename));
33
+ } else if (filename.endsWith("signtool.exe")) {
34
+ signToolPaths.push(filename);
35
+ }
36
+ });
37
+ return signToolPaths;
38
+ }
39
+ let signToolPaths = findSignTool(windowsSDKDir);
40
+ let latestWindowsSDKVersion = signToolPaths.map(x => x.replace(windowsSDKDir, "").split("\\")[0]).pop();
41
+ let latestWindowsSDKSignTools = signToolPaths.filter(x => x.startsWith(`${windowsSDKDir}${latestWindowsSDKVersion}`));
42
+ let x64SignTool = latestWindowsSDKSignTools.find(x => x.includes("x64"));
43
+ if (x64SignTool) {
44
+ return x64SignTool;
45
+ }
46
+ let x86SignTool = latestWindowsSDKSignTools.find(x => x.includes("x86"));
47
+ if (x86SignTool) {
48
+ return x86SignTool;
49
+ }
50
+ throw `No supported version for signtool installed in ${windowsSDKDir}${latestWindowsSdkVersion}`;
51
+ }
52
+
53
+ exports.getAppPath = function (opts) {
54
+ return "resources/app";
55
+ };
56
+
57
+ function patchExecutable(opts) {
58
+ return es.map(function (f, cb) {
59
+ if (
60
+ f.relative !== getOriginalAppFullName(opts) ||
61
+ process.platform !== "win32"
62
+ ) {
63
+ return cb(null, f);
64
+ }
65
+
66
+ var patch = {
67
+ "version-string": {
68
+ CompanyName: opts.companyName || "GitHub, Inc.",
69
+ FileDescription: opts.productAppName || opts.productName,
70
+ LegalCopyright:
71
+ opts.copyright ||
72
+ "Copyright (C) 2014 GitHub, Inc. All rights reserved",
73
+ ProductName: opts.productAppName || opts.productName,
74
+ ProductVersion: opts.productVersion,
75
+ },
76
+ "file-version": opts.productVersion,
77
+ "product-version": opts.productVersion,
78
+ };
79
+
80
+ if (opts.winIcon) {
81
+ patch.icon = opts.winIcon;
82
+ }
83
+
84
+ var tempPath = temp.path();
85
+ var ostream = fs.createWriteStream(tempPath);
86
+
87
+ f.contents.pipe(ostream);
88
+ ostream.on("close", function () {
89
+ // Remove codesignature before editing exe file
90
+ const signToolPath = getSignTool();
91
+ const {error} = spawnSync(signToolPath, ["remove", "/s", tempPath]);
92
+ if (error) {
93
+ return cb(error);
94
+ }
95
+
96
+ rcedit(tempPath, patch, function (err) {
97
+ if (err) {
98
+ return cb(err);
99
+ }
100
+
101
+ fs.readFile(tempPath, function (err, data) {
102
+ if (err) {
103
+ return cb(err);
104
+ }
105
+
106
+ f.contents = data;
107
+
108
+ fs.unlink(tempPath, function (err) {
109
+ if (err) {
110
+ return cb(err);
111
+ }
112
+
113
+ cb(null, f);
114
+ });
115
+ });
116
+ });
117
+ });
118
+ });
119
+ }
120
+
121
+ function removeDefaultApp() {
122
+ var defaultAppPath = path.join("resources", "default_app");
123
+
124
+ return es.mapSync(function (f) {
125
+ if (!f.relative.startsWith(defaultAppPath)) {
126
+ return f;
127
+ }
128
+ });
129
+ }
130
+
131
+ function renameApp(opts) {
132
+ return rename(function (path) {
133
+ if (
134
+ path.dirname === "." &&
135
+ path.basename === getOriginalAppName(opts) &&
136
+ path.extname === ".exe"
137
+ ) {
138
+ path.basename = opts.productName;
139
+ }
140
+ });
141
+ }
142
+
143
+ exports.patch = function (opts) {
144
+ var pass = es.through();
145
+
146
+ var src = pass
147
+ .pipe(opts.keepDefaultApp ? es.through() : removeDefaultApp())
148
+ .pipe(patchExecutable(opts))
149
+ .pipe(renameApp(opts));
150
+
151
+ return es.duplex(pass, src);
152
+ };