mirror of
https://github.com/S2-/gitlit
synced 2025-08-03 21:00:04 +02:00
186 lines
6.3 KiB
JavaScript
186 lines
6.3 KiB
JavaScript
'use strict'
|
|
|
|
const common = require('./common')
|
|
const debug = require('debug')('electron-packager')
|
|
const download = require('./download')
|
|
const extract = require('extract-zip')
|
|
const fs = require('fs-extra')
|
|
const getMetadataFromPackageJSON = require('./infer')
|
|
const hooks = require('./hooks')
|
|
const ignore = require('./ignore')
|
|
const nodeify = require('nodeify')
|
|
const path = require('path')
|
|
const pify = require('pify')
|
|
const targets = require('./targets')
|
|
|
|
function debugHostInfo () {
|
|
debug(common.hostInfo())
|
|
}
|
|
|
|
class Packager {
|
|
constructor (opts) {
|
|
this.opts = opts
|
|
this.tempBase = common.baseTempDir(opts)
|
|
this.useTempDir = opts.tmpdir !== false
|
|
this.canCreateSymlinks = undefined
|
|
}
|
|
|
|
ensureTempDir () {
|
|
if (this.useTempDir) {
|
|
return fs.remove(this.tempBase)
|
|
} else {
|
|
return Promise.resolve()
|
|
}
|
|
}
|
|
|
|
testSymlink (comboOpts, zipPath) {
|
|
const testPath = path.join(this.tempBase, 'symlink-test')
|
|
const testFile = path.join(testPath, 'test')
|
|
const testLink = path.join(testPath, 'testlink')
|
|
|
|
const cleanup = (symlinksWork) =>
|
|
fs.remove(testPath).then(() => symlinksWork)
|
|
|
|
return fs.outputFile(testFile, '')
|
|
.then(() => fs.symlink(testFile, testLink))
|
|
.then(() => cleanup(true))
|
|
.catch(/* istanbul ignore next */ () => cleanup(false))
|
|
.then(result => {
|
|
this.canCreateSymlinks = result
|
|
if (this.canCreateSymlinks) return this.checkOverwrite(comboOpts, zipPath)
|
|
|
|
/* istanbul ignore next */
|
|
return this.skipHostPlatformSansSymlinkSupport(comboOpts)
|
|
})
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
skipHostPlatformSansSymlinkSupport (comboOpts) {
|
|
common.info(`Cannot create symlinks (on Windows hosts, it requires admin privileges); skipping ${comboOpts.platform} platform`, this.opts.quiet)
|
|
return Promise.resolve()
|
|
}
|
|
|
|
overwriteAndCreateApp (outDir, comboOpts, zipPath) {
|
|
debug(`Removing ${outDir} due to setting overwrite: true`)
|
|
return fs.remove(outDir)
|
|
.then(() => this.createApp(comboOpts, zipPath))
|
|
}
|
|
|
|
extractElectronZip (comboOpts, zipPath, buildDir) {
|
|
debug(`Extracting ${zipPath} to ${buildDir}`)
|
|
return pify(extract)(zipPath, { dir: buildDir })
|
|
.then(() => hooks.promisifyHooks(this.opts.afterExtract, [buildDir, comboOpts.electronVersion, comboOpts.platform, comboOpts.arch]))
|
|
}
|
|
|
|
createApp (comboOpts, zipPath) {
|
|
let buildParentDir
|
|
if (this.useTempDir) {
|
|
buildParentDir = this.tempBase
|
|
} else {
|
|
buildParentDir = this.opts.out || process.cwd()
|
|
}
|
|
const buildDir = path.resolve(buildParentDir, `${comboOpts.platform}-${comboOpts.arch}-template`)
|
|
common.info(`Packaging app for platform ${comboOpts.platform} ${comboOpts.arch} using electron v${comboOpts.electronVersion}`, this.opts.quiet)
|
|
|
|
debug(`Creating ${buildDir}`)
|
|
return fs.ensureDir(buildDir)
|
|
.then(() => this.extractElectronZip(comboOpts, zipPath, buildDir))
|
|
.then(() => {
|
|
const os = require(targets.osModules[comboOpts.platform])
|
|
const app = new os.App(comboOpts, buildDir)
|
|
return app.create()
|
|
})
|
|
}
|
|
|
|
checkOverwrite (comboOpts, zipPath) {
|
|
const finalPath = common.generateFinalPath(comboOpts)
|
|
return fs.pathExists(finalPath)
|
|
.then(exists => {
|
|
if (exists) {
|
|
if (this.opts.overwrite) {
|
|
return this.overwriteAndCreateApp(finalPath, comboOpts, zipPath)
|
|
} else {
|
|
common.info(`Skipping ${comboOpts.platform} ${comboOpts.arch} (output dir already exists, use --overwrite to force)`, this.opts.quiet)
|
|
return true
|
|
}
|
|
} else {
|
|
return this.createApp(comboOpts, zipPath)
|
|
}
|
|
})
|
|
}
|
|
|
|
packageForPlatformAndArch (downloadOpts) {
|
|
return download.downloadElectronZip(downloadOpts)
|
|
.then(zipPath => {
|
|
// Create delegated options object with specific platform and arch, for output directory naming
|
|
const comboOpts = Object.assign({}, this.opts, {
|
|
arch: downloadOpts.arch,
|
|
platform: downloadOpts.platform,
|
|
electronVersion: downloadOpts.version
|
|
})
|
|
|
|
if (!this.useTempDir) {
|
|
return this.createApp(comboOpts, zipPath)
|
|
}
|
|
|
|
if (common.isPlatformMac(comboOpts.platform)) {
|
|
/* istanbul ignore else */
|
|
if (this.canCreateSymlinks === undefined) {
|
|
return this.testSymlink(comboOpts, zipPath)
|
|
} else if (!this.canCreateSymlinks) {
|
|
return this.skipHostPlatformSansSymlinkSupport(comboOpts)
|
|
}
|
|
}
|
|
|
|
return this.checkOverwrite(comboOpts, zipPath)
|
|
})
|
|
}
|
|
}
|
|
|
|
function packageAllSpecifiedCombos (opts, archs, platforms) {
|
|
const packager = new Packager(opts)
|
|
return packager.ensureTempDir()
|
|
.then(() => Promise.all(download.createDownloadCombos(opts, platforms, archs).map(
|
|
downloadOpts => packager.packageForPlatformAndArch(downloadOpts)
|
|
)))
|
|
}
|
|
|
|
function packagerPromise (opts) {
|
|
debugHostInfo()
|
|
if (debug.enabled) debug(`Packager Options: ${JSON.stringify(opts)}`)
|
|
|
|
const archs = targets.validateListFromOptions(opts, 'arch')
|
|
const platforms = targets.validateListFromOptions(opts, 'platform')
|
|
if (!Array.isArray(archs)) return Promise.reject(archs)
|
|
if (!Array.isArray(platforms)) return Promise.reject(platforms)
|
|
|
|
debug(`Target Platforms: ${platforms.join(', ')}`)
|
|
debug(`Target Architectures: ${archs.join(', ')}`)
|
|
|
|
const packageJSONDir = path.resolve(process.cwd(), opts.dir) || process.cwd()
|
|
|
|
return getMetadataFromPackageJSON(platforms, opts, packageJSONDir)
|
|
.then(() => {
|
|
if (opts.name.endsWith(' Helper')) {
|
|
throw new Error('Application names cannot end in " Helper" due to limitations on macOS')
|
|
}
|
|
|
|
debug(`Application name: ${opts.name}`)
|
|
debug(`Target Electron version: ${opts.electronVersion}`)
|
|
|
|
ignore.generateIgnores(opts)
|
|
|
|
return packageAllSpecifiedCombos(opts, archs, platforms)
|
|
})
|
|
// Remove falsy entries (e.g. skipped platforms)
|
|
.then(appPaths => appPaths.filter(appPath => appPath))
|
|
}
|
|
|
|
module.exports = function packager (opts, cb) {
|
|
if (cb) {
|
|
/* istanbul ignore next */
|
|
common.warning('The callback-based version of packager() is deprecated and will be removed in a future major version, please convert to the Promise version or use the nodeify module.')
|
|
}
|
|
return nodeify(packagerPromise(opts), cb)
|
|
}
|