Skip to content

Commit d9a8015

Browse files
committed
perf: use fcopy
1 parent 9ef77b9 commit d9a8015

File tree

22 files changed

+18517
-16713
lines changed

22 files changed

+18517
-16713
lines changed

.idea/dictionaries/develar.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/Options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ Configuration Options
258258
* <a name="NsisOptions-artifactName"></a>`artifactName` String - The [artifact file name pattern](https://github.com/electron-userland/electron-builder/wiki/Options#artifact-file-name-pattern). Defaults to `${productName} Setup ${version}.${ext}`.
259259
* <a name="NsisOptions-unicode"></a>`unicode` = `true` Boolean - Whether to create [Unicode installer](http://nsis.sourceforge.net/Docs/Chapter1.html#intro-unicode).
260260
* <a name="NsisOptions-deleteAppDataOnUninstall"></a>`deleteAppDataOnUninstall` = `false` Boolean - *one-click installer only.* Whether to delete app data on uninstall.
261+
* <a name="NsisOptions-packElevateHelper"></a>`packElevateHelper` = `true` Boolean - Whether to pack the elevate executable (required for electron-updater if per-machine installer used or can be used in the future). Ignored if `perMachine` is set to `true`.
261262
* <a name="Config-nsisWeb"></a>`nsisWeb`<a name="NsisWebOptions"></a> - Web Installer specific options.
262263
* <a name="NsisWebOptions-appPackageUrl"></a>`appPackageUrl` String - The application package download URL. Optional — by default computed using publish configuration.
263264

docs/api/electron-builder-util.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@
8383
* [.FileCopier](#FileCopier)
8484
* [`.copy(src, dest, stat)`](#module_electron-builder-util/out/fs.FileCopier+copy) ⇒ <code>Promise&lt;void&gt;</code>
8585
* [`.copyDir(src, destination, filter, transformer, isUseHardLink)`](#module_electron-builder-util/out/fs.copyDir) ⇒ <code>Promise&lt;any&gt;</code>
86-
* [`.copyFile(src, dest, stats, isUseHardLink)`](#module_electron-builder-util/out/fs.copyFile) ⇒ <code>Promise&lt;any&gt;</code>
86+
* [`.copyFile(src, dest, isEnsureDir)`](#module_electron-builder-util/out/fs.copyFile) ⇒ <code>Promise&lt;any&gt;</code>
87+
* [`.copyOrLinkFile(src, dest, stats, isUseHardLink)`](#module_electron-builder-util/out/fs.copyOrLinkFile) ⇒ <code>Promise&lt;any&gt;</code>
8788
* [`.exists(file)`](#module_electron-builder-util/out/fs.exists) ⇒ <code>Promise&lt;Boolean&gt;</code>
8889
* [`.statOrNull(file)`](#module_electron-builder-util/out/fs.statOrNull) ⇒ <code>Promise&lt; \| module:fs.Stats&gt;</code>
8990
* [`.unlinkIfExists(file)`](#module_electron-builder-util/out/fs.unlinkIfExists) ⇒ <code>Promise&lt;String \| void&gt;</code>
@@ -122,10 +123,23 @@ Hard links is used if supported and allowed.
122123

123124
<a name="module_electron-builder-util/out/fs.copyFile"></a>
124125

125-
### `electron-builder-util/out/fs.copyFile(src, dest, stats, isUseHardLink)` ⇒ <code>Promise&lt;any&gt;</code>
126+
### `electron-builder-util/out/fs.copyFile(src, dest, isEnsureDir)` ⇒ <code>Promise&lt;any&gt;</code>
127+
**Kind**: method of [<code>electron-builder-util/out/fs</code>](#module_electron-builder-util/out/fs)
128+
129+
| Param | Type |
130+
| --- | --- |
131+
| src | <code>String</code> |
132+
| dest | <code>String</code> |
133+
| isEnsureDir | |
134+
135+
<a name="module_electron-builder-util/out/fs.copyOrLinkFile"></a>
136+
137+
### `electron-builder-util/out/fs.copyOrLinkFile(src, dest, stats, isUseHardLink)` ⇒ <code>Promise&lt;any&gt;</code>
126138
Hard links is used if supported and allowed.
127139
File permission is fixed — allow execute for all if owner can, allow read for all if owner can.
128140

141+
ensureDir is not called, dest parent dir must exists
142+
129143
**Kind**: method of [<code>electron-builder-util/out/fs</code>](#module_electron-builder-util/out/fs)
130144

131145
| Param | Type |

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"electron-download-tf": "4.3.1",
4141
"electron-is-dev": "^0.1.2",
4242
"electron-osx-sign": "0.4.6",
43+
"fcopy-pre-bundled": "^0.1.2",
4344
"fs-extra-p": "^4.3.0",
4445
"hosted-git-info": "^2.4.2",
4546
"ini": "^1.3.4",

packages/electron-builder-squirrel-windows/src/squirrelPack.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { debug, exec, execWine, prepareArgs, spawn } from "electron-builder-util
33
import { copyFile, walk } from "electron-builder-util/out/fs"
44
import { log } from "electron-builder-util/out/log"
55
import { WinPackager } from "electron-builder/out/winPackager"
6-
import { copy, createWriteStream, ensureDir, remove, stat, unlink } from "fs-extra-p"
6+
import { createWriteStream, ensureDir, remove, stat, unlink } from "fs-extra-p"
77
import * as path from "path"
88

99
const archiver = require("archiver")
@@ -50,7 +50,7 @@ export interface SquirrelOptions {
5050
export async function buildInstaller(options: SquirrelOptions, outputDirectory: string, setupExe: string, packager: WinPackager, appOutDir: string) {
5151
const appUpdate = await packager.getTempFile("Update.exe")
5252
await BluebirdPromise.all([
53-
copy(path.join(options.vendorPath, "Update.exe"), appUpdate)
53+
copyFile(path.join(options.vendorPath, "Update.exe"), appUpdate)
5454
.then(() => packager.sign(appUpdate)),
5555
BluebirdPromise.all([remove(`${outputDirectory.replace(/\\/g, "/")}/*-full.nupkg`), remove(path.join(outputDirectory, "RELEASES"))])
5656
.then(() => ensureDir(outputDirectory))
@@ -79,7 +79,7 @@ export async function buildInstaller(options: SquirrelOptions, outputDirectory:
7979

8080
await BluebirdPromise.all<any>([
8181
pack(options, appOutDir, appUpdate, nupkgPath, version, packager),
82-
copy(path.join(options.vendorPath, "Setup.exe"), setupPath),
82+
copyFile(path.join(options.vendorPath, "Setup.exe"), setupPath),
8383
])
8484

8585
embeddedArchive.file(nupkgPath, {name: packageName})
@@ -233,7 +233,7 @@ async function encodedZip(archive: any, dir: string, prefix: string, vendorPath:
233233
// createExecutableStubForExe
234234
if (file.endsWith(".exe") && !file.includes("squirrel.exe")) {
235235
const tempFile = await packager.getTempFile("stub.exe")
236-
await copyFile(path.join(vendorPath, "StubExecutable.exe"), tempFile, null, false)
236+
await copyFile(path.join(vendorPath, "StubExecutable.exe"), tempFile)
237237
await execWine(path.join(vendorPath, "WriteZipToSetup.exe"), ["--copy-stub-resources", file, tempFile])
238238
await packager.sign(tempFile)
239239

packages/electron-builder-util/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
],
1313
"dependencies": {
1414
"fs-extra-p": "^4.3.0",
15+
"fcopy-pre-bundled": "^0.1.2",
1516
"is-ci": "^1.0.10",
1617
"stat-mode": "^0.2.2",
1718
"bluebird-lst": "^1.0.2",

packages/electron-builder-util/src/fs.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import BluebirdPromise from "bluebird-lst"
2-
import { access, createReadStream, createWriteStream, link, lstat, mkdirs, readdir, readlink, stat, Stats, symlink, unlink, writeFile } from "fs-extra-p"
2+
import fcopy from "fcopy-pre-bundled"
3+
import { access, ensureDir, link, lstat, readdir, readlink, stat, Stats, symlink, unlink, writeFile } from "fs-extra-p"
34
import isCi from "is-ci"
45
import * as path from "path"
56
import Mode from "stat-mode"
@@ -109,11 +110,17 @@ export async function walk(initialDirPath: string, filter?: Filter | null, consu
109110

110111
const _isUseHardLink = process.platform != "win32" && process.env.USE_HARD_LINKS !== "false" && (isCi || process.env.USE_HARD_LINKS === "true")
111112

113+
export function copyFile(src: string, dest: string, isEnsureDir = true) {
114+
return (isEnsureDir ? ensureDir(path.dirname(dest)) : BluebirdPromise.resolve()).then(() => copyOrLinkFile(src, dest, null, false))
115+
}
116+
112117
/**
113118
* Hard links is used if supported and allowed.
114119
* File permission is fixed — allow execute for all if owner can, allow read for all if owner can.
120+
*
121+
* ensureDir is not called, dest parent dir must exists
115122
*/
116-
export function copyFile(src: string, dest: string, stats?: Stats | null, isUseHardLink = _isUseHardLink): Promise<any> {
123+
export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null, isUseHardLink = _isUseHardLink): Promise<any> {
117124
if (stats != null) {
118125
const originalModeNumber = stats.mode
119126
const mode = new Mode(stats)
@@ -146,17 +153,7 @@ export function copyFile(src: string, dest: string, stats?: Stats | null, isUseH
146153
}
147154

148155
return new BluebirdPromise(function (resolve, reject) {
149-
const readStream = createReadStream(src)
150-
const writeStream = createWriteStream(dest, stats == null ? undefined : {mode: stats.mode})
151-
152-
readStream.on("error", reject)
153-
writeStream.on("error", reject)
154-
155-
writeStream.on("open", function () {
156-
readStream.pipe(writeStream)
157-
})
158-
159-
writeStream.once("close", resolve)
156+
fcopy(src, dest, stats == null ? undefined : {mode: stats.mode}, error => error == null ? resolve() : reject(error))
160157
})
161158
}
162159

@@ -181,7 +178,7 @@ export class FileCopier {
181178
}
182179
}
183180
}
184-
await copyFile(src, dest, stat, (!this.isUseHardLink || this.isUseHardLinkFunction == null) ? this.isUseHardLink : this.isUseHardLinkFunction(dest))
181+
await copyOrLinkFile(src, dest, stat, (!this.isUseHardLink || this.isUseHardLinkFunction == null) ? this.isUseHardLink : this.isUseHardLinkFunction(dest))
185182
}
186183
catch (e) {
187184
// files are copied concurrently, so, we must not check here currentIsUseHardLink — our code can be executed after that other handler will set currentIsUseHardLink to false
@@ -192,7 +189,7 @@ export class FileCopier {
192189
this.isUseHardLink = false
193190
}
194191

195-
await copyFile(src, dest, stat, false)
192+
await copyOrLinkFile(src, dest, stat, false)
196193
}
197194
else {
198195
throw e
@@ -219,7 +216,7 @@ export function copyDir(src: string, destination: string, filter?: Filter, trans
219216
}
220217

221218
if (!createdSourceDirs.has(parent)) {
222-
await mkdirs(parent.replace(src, destination))
219+
await ensureDir(parent.replace(src, destination))
223220
createdSourceDirs.add(parent)
224221
}
225222

packages/electron-builder-util/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"../../typings/debug.d.ts",
1919
"../../typings/node-emoji.d.ts",
2020
"../../typings/pretty-ms.d.ts",
21-
"../../typings/ansi-escapes.d.ts"
21+
"../../typings/ansi-escapes.d.ts",
22+
"../../typings/fcopy-pre-bundled.d.ts"
2223
]
2324
}

packages/electron-builder/src/codeSign.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import BluebirdPromise from "bluebird-lst"
22
import { randomBytes } from "crypto"
33
import { exec, getCacheDirectory, getTempName, isEmptyOrSpaces } from "electron-builder-util"
4-
import { statOrNull } from "electron-builder-util/out/fs"
4+
import { copyFile, statOrNull } from "electron-builder-util/out/fs"
55
import { httpExecutor } from "electron-builder-util/out/nodeHttpExecutor"
66
import { all, executeFinally } from "electron-builder-util/out/promise"
77
import { TmpDir } from "electron-builder-util/out/tmp"
8-
import { copy, deleteFile, outputFile, rename } from "fs-extra-p"
8+
import { deleteFile, outputFile, rename } from "fs-extra-p"
99
import isCi from "is-ci"
1010
import { homedir } from "os"
1111
import * as path from "path"
@@ -73,7 +73,7 @@ async function createCustomCertKeychain() {
7373
const keychainPath = path.join(getCacheDirectory(), "electron-builder-root-certs.keychain")
7474
const results = await BluebirdPromise.all<string>([
7575
exec("security", ["list-keychains"]),
76-
copy(path.join(__dirname, "..", "certs", "root_certs.keychain"), tmpKeychainPath)
76+
copyFile(path.join(__dirname, "..", "certs", "root_certs.keychain"), tmpKeychainPath)
7777
.then(() => rename(tmpKeychainPath, keychainPath)),
7878
])
7979
const list = results[0]

packages/electron-builder/src/fileMatcher.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import BluebirdPromise from "bluebird-lst"
22
import { asArray, debug } from "electron-builder-util"
3-
import { copyDir, copyFile, Filter, statOrNull } from "electron-builder-util/out/fs"
3+
import { copyDir, copyOrLinkFile, Filter, statOrNull } from "electron-builder-util/out/fs"
44
import { warn } from "electron-builder-util/out/log"
55
import { mkdirs } from "fs-extra-p"
66
import { Minimatch } from "minimatch"
@@ -183,11 +183,11 @@ export function copyFiles(patterns: Array<FileMatcher> | null): Promise<any> {
183183
const toStat = await statOrNull(pattern.to)
184184
// https://github.com/electron-userland/electron-builder/issues/1245
185185
if (toStat != null && toStat.isDirectory()) {
186-
return await copyFile(pattern.from, path.join(pattern.to, path.basename(pattern.from)), fromStat)
186+
return await copyOrLinkFile(pattern.from, path.join(pattern.to, path.basename(pattern.from)), fromStat)
187187
}
188188

189189
await mkdirs(path.dirname(pattern.to))
190-
return await copyFile(pattern.from, pattern.to, fromStat)
190+
return await copyOrLinkFile(pattern.from, pattern.to, fromStat)
191191
}
192192

193193
if (pattern.isEmpty() || pattern.containsOnlyIgnore()) {

0 commit comments

Comments
 (0)