feat: initial build
This commit is contained in:
@@ -1,62 +0,0 @@
|
||||
import { join, dirname } from 'path'
|
||||
import { readdir, unlink } from 'fs'
|
||||
import { readFileAsync, writeFileAsync, isDirectoryAsync } from './util'
|
||||
import { promisify, map } from 'bluebird'
|
||||
import * as mkdirp from 'mkdirp'
|
||||
import { NexeCompiler } from './compiler'
|
||||
|
||||
const mkdirpAsync = promisify(mkdirp)
|
||||
const unlinkAsync = (promisify(unlink) as any) as (path: string) => PromiseLike<void>
|
||||
const readdirAsync = promisify(readdir)
|
||||
|
||||
function readDirAsync(dir: string): PromiseLike<string[]> {
|
||||
return readdirAsync(dir)
|
||||
.map((file: string) => {
|
||||
const path = join(dir, file)
|
||||
return isDirectoryAsync(path).then((x: boolean) => (x ? readDirAsync(path) : path as any))
|
||||
})
|
||||
.reduce((a: string[], b: string[] | string) => a.concat(b), [])
|
||||
}
|
||||
|
||||
function maybeReadFileContentsAsync(file: string) {
|
||||
return readFileAsync(file, 'utf-8').catch(e => {
|
||||
if (e.code === 'ENOENT') {
|
||||
return ''
|
||||
}
|
||||
throw e
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* The artifacts step is where source patches are committed, or written as "artifacts"
|
||||
* Steps:
|
||||
* - A temporary directory is created in the downloaded source
|
||||
* - On start, any files in that directory are restored into the source tree
|
||||
* - After the patch functions have run, the temporary directory is emptied
|
||||
* - Original versions of sources to be patched are written to the temporary directory
|
||||
* - Finally, The patched files are written into source.
|
||||
*
|
||||
*/
|
||||
export default async function artifacts(compiler: NexeCompiler, next: () => Promise<void>) {
|
||||
const { src } = compiler
|
||||
const temp = join(src, 'nexe')
|
||||
await mkdirpAsync(temp)
|
||||
const tmpFiles = await readDirAsync(temp)
|
||||
|
||||
await map(tmpFiles, async path => {
|
||||
return compiler.writeFileAsync(path.replace(temp, ''), await readFileAsync(path, 'utf-8'))
|
||||
})
|
||||
|
||||
await next()
|
||||
|
||||
await map(tmpFiles, x => unlinkAsync(x))
|
||||
return map(compiler.files, async file => {
|
||||
const sourceFile = join(src, file.filename)
|
||||
const tempFile = join(temp, file.filename)
|
||||
const fileContents = await maybeReadFileContentsAsync(sourceFile)
|
||||
|
||||
await mkdirpAsync(dirname(tempFile))
|
||||
await writeFileAsync(tempFile, fileContents)
|
||||
await compiler.writeFileAsync(file.filename, file.contents)
|
||||
})
|
||||
}
|
||||
+18
-6
@@ -1,9 +1,18 @@
|
||||
import { NexeCompiler } from '../compiler'
|
||||
import { FuseBox, JSONPlugin, CSSPlugin, HTMLPlugin, SourceMapPlainJsPlugin } from 'fuse-box'
|
||||
import { FuseBox, JSONPlugin, CSSPlugin, HTMLPlugin, QuantumPlugin } from 'fuse-box'
|
||||
//import NativeModulePlugin from './fuse-native-module-plugin'
|
||||
|
||||
function bundleProducer(filename: string, name: string) {
|
||||
console.error(process.cwd())
|
||||
function bundleProducer(filename: string, options: { name: string; minify: any }) {
|
||||
const plugins: any = [JSONPlugin(), CSSPlugin(), HTMLPlugin()]
|
||||
if (options.minify) {
|
||||
plugins.push(
|
||||
QuantumPlugin({
|
||||
target: 'server',
|
||||
uglify: true,
|
||||
bakeApiIntoBundle: options.name
|
||||
})
|
||||
)
|
||||
}
|
||||
const fuse = FuseBox.init({
|
||||
cache: false,
|
||||
log: Boolean(process.env.NEXE_BUNDLE_DEBUG) || false,
|
||||
@@ -12,9 +21,9 @@ function bundleProducer(filename: string, name: string) {
|
||||
writeBundles: false,
|
||||
output: '$name.js',
|
||||
target: 'server',
|
||||
plugins: [JSONPlugin(), CSSPlugin(), HTMLPlugin(), SourceMapPlainJsPlugin()]
|
||||
plugins
|
||||
})
|
||||
fuse.bundle(name).instructions(`> ${filename}`)
|
||||
fuse.bundle(options.name).instructions(`> ${filename}`)
|
||||
return fuse.run().then(x => {
|
||||
let output = ''
|
||||
x.bundles.forEach(y => (output = y.context.output.lastPrimaryOutput.content!.toString()))
|
||||
@@ -32,6 +41,9 @@ export default async function bundle(compiler: NexeCompiler, next: any) {
|
||||
producer = require(compiler.options.bundle).bundleProducer
|
||||
}
|
||||
|
||||
compiler.input = await producer(compiler.options.input, compiler.options.name)
|
||||
compiler.input = await producer(compiler.options.input, {
|
||||
name: compiler.options.name,
|
||||
minify: compiler.options.compress
|
||||
})
|
||||
return next()
|
||||
}
|
||||
|
||||
+14
-15
@@ -1,14 +1,13 @@
|
||||
import { normalize, join } from 'path'
|
||||
import * as Bluebird from 'bluebird'
|
||||
import { Buffer } from 'buffer'
|
||||
import { createHash } from 'crypto'
|
||||
import { createReadStream } from 'fs'
|
||||
import { Readable } from 'stream'
|
||||
import { spawn } from 'child_process'
|
||||
import { Stream as Needle } from 'nigel'
|
||||
import { Logger } from './logger'
|
||||
import { readFileAsync, writeFileAsync, pathExistsAsync, dequote, isWindows } from './util'
|
||||
import { NexeOptions } from './options'
|
||||
import { NexeOptions, nexeVersion } from './options'
|
||||
import { NexeTarget } from './target'
|
||||
|
||||
const isBsd = Boolean(~process.platform.indexOf('bsd'))
|
||||
const make = isWindows ? 'vcbuild.bat' : isBsd ? 'gmake' : 'make'
|
||||
@@ -51,7 +50,7 @@ export class NexeCompiler {
|
||||
|
||||
constructor(public options: NexeOptions) {
|
||||
const { python } = (this.options = options)
|
||||
|
||||
this.log.step('nexe ' + nexeVersion, 'info')
|
||||
if (python) {
|
||||
if (isWindows) {
|
||||
this.env.PATH = '"' + dequote(normalize(python)) + '";' + this.env.PATH
|
||||
@@ -67,7 +66,10 @@ export class NexeCompiler {
|
||||
cachedFile = {
|
||||
absPath,
|
||||
filename: file,
|
||||
contents: await readFileAsync(absPath, 'utf-8').catch({ code: 'ENOENT' }, () => '')
|
||||
contents: await readFileAsync(absPath, 'utf-8').catch(x => {
|
||||
if (x.code === 'ENOENT') return ''
|
||||
throw x
|
||||
})
|
||||
}
|
||||
this.files.push(cachedFile)
|
||||
}
|
||||
@@ -84,21 +86,21 @@ export class NexeCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
quit(code = 0) {
|
||||
quit() {
|
||||
const time = Date.now() - this.start
|
||||
this.log.write(`Finsihed in ${time / 1000}s`)
|
||||
return this.log.flush().then(x => process.exit(code))
|
||||
return this.log.flush()
|
||||
}
|
||||
|
||||
private _getNodeExecutableLocation(target?: string | null) {
|
||||
private _getNodeExecutableLocation(target?: NexeTarget) {
|
||||
if (target) {
|
||||
return join(this.options.temp, target)
|
||||
return join(this.options.temp, target.toString())
|
||||
}
|
||||
return this.nodeSrcBinPath
|
||||
}
|
||||
|
||||
private _runBuildCommandAsync(command: string, args: string[]) {
|
||||
return new Bluebird((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
spawn(command, args, {
|
||||
cwd: this.src,
|
||||
env: this.env,
|
||||
@@ -123,7 +125,7 @@ export class NexeCompiler {
|
||||
: '...'}`
|
||||
)
|
||||
await this._configureAsync()
|
||||
const buildOptions = isWindows ? this.options.vcBuild : this.options.make
|
||||
const buildOptions = this.options.make
|
||||
this.compileStep.log(
|
||||
`Compiling Node${buildOptions.length ? ' with arguments: ' + buildOptions : '...'}`
|
||||
)
|
||||
@@ -152,16 +154,13 @@ export class NexeCompiler {
|
||||
return `process.__nexe=${JSON.stringify(header)};`
|
||||
}
|
||||
|
||||
async compileAsync() {
|
||||
async compileAsync(target: NexeTarget) {
|
||||
const step = (this.compileStep = this.log.step('Compiling result'))
|
||||
let target = this.options.targets.slice().shift()
|
||||
const location = this._getNodeExecutableLocation(target)
|
||||
let binary = (await pathExistsAsync(location)) ? createReadStream(location) : null
|
||||
const header = this._generateHeader()
|
||||
step.log(`Scanning existing binary...`)
|
||||
|
||||
if (target && !binary) {
|
||||
//throw new Error('\nNot Implemented, use --build during beta\n')
|
||||
binary = await this._fetchPrebuiltBinaryAsync()
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -46,14 +46,17 @@ export class Logger {
|
||||
this.ora.color = color
|
||||
}
|
||||
|
||||
step(text: string): LogStep {
|
||||
step(text: string, method: string = 'succeed'): LogStep {
|
||||
if (this.silent) {
|
||||
return { modify() {}, log() {} }
|
||||
}
|
||||
if (!this.ora.id) {
|
||||
this.ora.start().text = text
|
||||
if (method !== 'succeed') {
|
||||
this.ora[method]()
|
||||
}
|
||||
} else {
|
||||
this.ora.succeed().text = text
|
||||
this.ora[method]().text = text
|
||||
this.ora.start()
|
||||
}
|
||||
|
||||
|
||||
+19
-11
@@ -1,18 +1,18 @@
|
||||
import { compose, PromiseConfig, Middleware } from 'app-builder'
|
||||
import resource from './resource'
|
||||
import resource from './steps/resource'
|
||||
import { NexeCompiler } from './compiler'
|
||||
import { argv, normalizeOptionsAsync, NexeOptions } from './options'
|
||||
import cli from './cli'
|
||||
import { argv, normalizeOptionsAsync, NexeOptions, NexePatch } from './options'
|
||||
import cli from './steps/cli'
|
||||
import bundle from './bundling/fuse'
|
||||
import download from './download'
|
||||
import artifacts from './artifacts'
|
||||
import download from './steps/download'
|
||||
import artifacts from './steps/artifacts'
|
||||
import patches from './patches'
|
||||
import { rimrafAsync } from './util'
|
||||
import * as Bluebird from 'bluebird'
|
||||
|
||||
PromiseConfig.constructor = Bluebird
|
||||
|
||||
async function compile(compilerOptions: NexeOptions, callback?: (err: Error | null) => void) {
|
||||
async function compile(
|
||||
compilerOptions?: Partial<NexeOptions>,
|
||||
callback?: (err: Error | null) => void
|
||||
) {
|
||||
const options = await normalizeOptionsAsync(compilerOptions)
|
||||
const compiler = new NexeCompiler(options)
|
||||
const build = compiler.options.build
|
||||
@@ -25,9 +25,17 @@ async function compile(compilerOptions: NexeOptions, callback?: (err: Error | nu
|
||||
return compiler.quit()
|
||||
}
|
||||
|
||||
const buildSteps = build ? [download, artifacts, ...patches, ...options.patches] : []
|
||||
const buildSteps = build
|
||||
? [download, artifacts, ...patches, ...(options.patches as NexePatch[])]
|
||||
: []
|
||||
const nexe = compose(resource, bundle, cli, buildSteps)
|
||||
return nexe(compiler).asCallback(callback)
|
||||
return callback
|
||||
? void nexe(compiler).then(() => callback && callback(null)).catch((e: Error) => {
|
||||
if (callback) {
|
||||
callback(e)
|
||||
} else throw e
|
||||
})
|
||||
: nexe(compiler)
|
||||
}
|
||||
|
||||
export { argv, compile }
|
||||
|
||||
+39
-57
@@ -1,72 +1,49 @@
|
||||
import * as parseArgv from 'minimist'
|
||||
import { NexeCompiler } from './compiler'
|
||||
import { basename, extname, join } from 'path'
|
||||
import * as Bluebird from 'bluebird'
|
||||
import { isWindows } from './util'
|
||||
import { basename, extname, join, isAbsolute } from 'path'
|
||||
import { getTarget, NexeTarget } from './target'
|
||||
import { EOL } from 'os'
|
||||
|
||||
export const nexeVersion = '2.0.0-rc.1'
|
||||
|
||||
export interface NexePatch {
|
||||
(compiler: NexeCompiler, next: () => Promise<void>): Promise<void>
|
||||
}
|
||||
|
||||
export interface NexeOptions {
|
||||
build: boolean
|
||||
/**
|
||||
* Entrypoint filepath
|
||||
*/
|
||||
input: string
|
||||
output: string
|
||||
targets: string[]
|
||||
/**
|
||||
* Build name, Used for executable, and stacktraces
|
||||
*/
|
||||
compress: boolean
|
||||
targets: (string | NexeTarget)[]
|
||||
name: string
|
||||
/**
|
||||
* The node version to be built
|
||||
*/
|
||||
version: string
|
||||
python?: string
|
||||
/**
|
||||
* Node flags e.g. "--expose-gc" baked into the executable
|
||||
*/
|
||||
flags: string[]
|
||||
/**
|
||||
* Pass configuration options to node build configure script
|
||||
*/
|
||||
configure: string[]
|
||||
/**
|
||||
* Pass make options to node make script
|
||||
*/
|
||||
make: string[]
|
||||
vcBuild: string[]
|
||||
make: string[]
|
||||
snapshot?: string
|
||||
/**
|
||||
* Array of glob strings describing resources to pull into the bundle
|
||||
*/
|
||||
resources: string[]
|
||||
/**
|
||||
* Temporary directory where nexe artifacts will be cached
|
||||
* TODO dot folder in home dir
|
||||
*/
|
||||
temp: string
|
||||
ico?: string
|
||||
sourceMaps?: boolean
|
||||
rc: { [key: string]: string }
|
||||
/**
|
||||
* Causes nexe to remove all temporary files for current configuration
|
||||
*/
|
||||
clean: boolean
|
||||
enableNodeCli: boolean
|
||||
sourceUrl?: string
|
||||
bundle: boolean | string
|
||||
patches: (string | NexePatch)[]
|
||||
empty: boolean
|
||||
sourceUrl?: string
|
||||
python?: string
|
||||
loglevel: 'info' | 'silent' | 'verbose'
|
||||
silent?: boolean
|
||||
verbose?: boolean
|
||||
info?: boolean
|
||||
patches: NexePatch[]
|
||||
|
||||
empty: boolean
|
||||
ico?: string
|
||||
warmup?: string
|
||||
downloadOptions?: any
|
||||
clean?: boolean
|
||||
/**
|
||||
* Api Only
|
||||
*/
|
||||
downloadOptions: any
|
||||
}
|
||||
|
||||
function padRight(str: string, l: number) {
|
||||
@@ -80,10 +57,11 @@ const defaults = {
|
||||
configure: [],
|
||||
make: [],
|
||||
targets: [],
|
||||
vcBuild: ['nosign', 'release', process.arch],
|
||||
vcBuild: isWindows ? ['nosign', 'release', process.arch] : [],
|
||||
enableNodeCli: false,
|
||||
compress: false,
|
||||
build: false,
|
||||
bundle: true,
|
||||
build: true,
|
||||
patches: []
|
||||
}
|
||||
const alias = {
|
||||
@@ -98,9 +76,7 @@ const alias = {
|
||||
f: 'flag',
|
||||
c: 'configure',
|
||||
m: 'make',
|
||||
vc: 'vcBuild',
|
||||
s: 'snapshot',
|
||||
cli: 'enableNodeCli',
|
||||
h: 'help',
|
||||
l: 'loglevel'
|
||||
}
|
||||
@@ -117,9 +93,8 @@ nexe --help CLI OPTIONS
|
||||
-v --version =${padRight(process.version.slice(1), 23)}-- node version
|
||||
-p --python =/path/to/python2 -- python executable
|
||||
-f --flag ="--expose-gc" -- *v8 flags to include during compilation
|
||||
-c --configure ="--with-dtrace" -- *pass arguments to the configure command
|
||||
-m --make ="--loglevel" -- *pass arguments to the make command
|
||||
-vc --vcBuild =x64 -- *pass arguments to vcbuild.bat
|
||||
-c --configure ="--with-dtrace" -- *pass arguments to the configure step
|
||||
-m --make ="--loglevel" -- *pass arguments to the make/build step
|
||||
-s --snapshot =/path/to/snapshot -- build with warmup snapshot
|
||||
-r --resource =./paths/**/* -- *embed file bytes within the binary
|
||||
--bundle =./path/to/config -- pass a module path that exports nexeBundle
|
||||
@@ -182,20 +157,20 @@ function extractName(options: NexeOptions) {
|
||||
return name.replace(/\.exe$/, '')
|
||||
}
|
||||
|
||||
function normalizeOptionsAsync(input: Partial<NexeOptions>) {
|
||||
if (argv.help || argv._.some((x: string) => x === 'version')) {
|
||||
process.stderr.write(argv.help ? help : '2.0.0-rc.1' + EOL, () => process.exit(0))
|
||||
function normalizeOptionsAsync(input?: Partial<NexeOptions>): Promise<NexeOptions | never> {
|
||||
if (argv.help || argv._.some((x: string) => x === 'version') || argv.version === true) {
|
||||
return new Promise(() => {
|
||||
process.stderr.write(argv.help ? help : nexeVersion + EOL, () => process.exit(0))
|
||||
})
|
||||
}
|
||||
|
||||
const options = Object.assign({}, defaults, input) as NexeOptions
|
||||
const opts = options as any
|
||||
delete opts._
|
||||
|
||||
options.loglevel = extractLogLevel(options)
|
||||
options.name = extractName(options)
|
||||
options.flags = flattenFilter(opts.flag, options.flags)
|
||||
options.targets = flattenFilter(opts.target, options.targets)
|
||||
options.make = flattenFilter(options.make)
|
||||
options.vcBuild = flattenFilter(options.vcBuild)
|
||||
options.make = flattenFilter(options.vcBuild, options.make)
|
||||
options.configure = flattenFilter(options.configure)
|
||||
options.resources = flattenFilter(opts.resource, options.resources)
|
||||
options.rc = options.rc || extractCliMap(/^rc-.*/, options)
|
||||
@@ -204,10 +179,17 @@ function normalizeOptionsAsync(input: Partial<NexeOptions>) {
|
||||
options.targets = []
|
||||
options.build = true
|
||||
} else if (!options.targets.length) {
|
||||
const defaultTarget = [process.platform, process.arch, options.version].join('-')
|
||||
options.targets = [defaultTarget]
|
||||
options.targets = [getTarget()]
|
||||
}
|
||||
|
||||
options.targets = options.targets.map(getTarget)
|
||||
options.patches = options.patches.map(x => {
|
||||
if (typeof x === 'string') {
|
||||
return require(x).default
|
||||
}
|
||||
return x
|
||||
})
|
||||
|
||||
Object.keys(alias).filter(k => k !== 'rc').forEach(x => delete opts[x])
|
||||
|
||||
return Promise.resolve(options)
|
||||
|
||||
@@ -3,11 +3,6 @@ import { readFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
|
||||
export default async function main(compiler: NexeCompiler, next: () => Promise<void>) {
|
||||
let sourceMapSupport = ''
|
||||
if (true /*compiler.options.sourceMaps*/) {
|
||||
sourceMapSupport = readFileSync(join(__dirname, '../../source-map-support.js')).toString()
|
||||
}
|
||||
|
||||
await compiler.setFileContentsAsync(
|
||||
'lib/_third_party_main.js',
|
||||
`
|
||||
@@ -21,7 +16,7 @@ const footer = Buffer.from(Array(32))
|
||||
fs.readSync(fd, footer, 0, 32, size - 32)
|
||||
|
||||
if (!footer.slice(0, 16).equals(Buffer.from('<nexe~~sentinel>'))) {
|
||||
throw new Error('Invalid Nexe binary')
|
||||
throw 'Invalid Nexe binary'
|
||||
}
|
||||
|
||||
const contentSize = footer.readDoubleLE(16)
|
||||
@@ -102,7 +97,6 @@ if (resourceSize) {
|
||||
const contentBuffer = Buffer.from(Array(contentSize));
|
||||
fs.readSync(fd, contentBuffer, 0, contentSize, contentStart);
|
||||
fs.closeSync(fd);
|
||||
${sourceMapSupport}
|
||||
const Module = require('module');
|
||||
process.mainModule = new Module(process.execPath, null);
|
||||
process.mainModule.loaded = true;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { join, dirname } from 'path'
|
||||
import { readdir, unlink } from 'fs'
|
||||
import { readFileAsync, writeFileAsync, isDirectoryAsync } from '../util'
|
||||
import * as mkdirp from 'mkdirp'
|
||||
import { NexeCompiler } from '../compiler'
|
||||
import pify = require('pify')
|
||||
|
||||
const mkdirpAsync = pify(mkdirp)
|
||||
const unlinkAsync = pify(unlink)
|
||||
const readdirAsync = pify(readdir)
|
||||
|
||||
function readDirAsync(dir: string): Promise<string[]> {
|
||||
return readdirAsync(dir).then(paths => {
|
||||
return Promise.all(
|
||||
paths.map((file: string) => {
|
||||
const path = join(dir, file)
|
||||
return isDirectoryAsync(path).then(x => (x ? readDirAsync(path) : path as any))
|
||||
})
|
||||
).then(result => {
|
||||
return [].concat(...(result as any))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function maybeReadFileContentsAsync(file: string) {
|
||||
return readFileAsync(file, 'utf-8').catch(e => {
|
||||
if (e.code === 'ENOENT') {
|
||||
return ''
|
||||
}
|
||||
throw e
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* The artifacts step is where source patches are committed, or written as "artifacts"
|
||||
* Steps:
|
||||
* - A temporary directory is created in the downloaded source
|
||||
* - On start, any files in that directory are restored into the source tree
|
||||
* - After the patch functions have run, the temporary directory is emptied
|
||||
* - Original versions of sources to be patched are written to the temporary directory
|
||||
* - Finally, The patched files are written into source.
|
||||
*
|
||||
*/
|
||||
export default async function artifacts(compiler: NexeCompiler, next: () => Promise<void>) {
|
||||
const { src } = compiler
|
||||
const temp = join(src, 'nexe')
|
||||
await mkdirpAsync(temp)
|
||||
const tmpFiles = await readDirAsync(temp)
|
||||
|
||||
await Promise.all(
|
||||
tmpFiles.map(async path => {
|
||||
return compiler.writeFileAsync(path.replace(temp, ''), await readFileAsync(path, 'utf-8'))
|
||||
})
|
||||
)
|
||||
|
||||
await next()
|
||||
|
||||
await Promise.all(tmpFiles.map(x => unlinkAsync(x)))
|
||||
return Promise.all(
|
||||
compiler.files.map(async file => {
|
||||
const sourceFile = join(src, file.filename)
|
||||
const tempFile = join(temp, file.filename)
|
||||
const fileContents = await maybeReadFileContentsAsync(sourceFile)
|
||||
|
||||
await mkdirpAsync(dirname(tempFile))
|
||||
await writeFileAsync(tempFile, fileContents)
|
||||
await compiler.writeFileAsync(file.filename, file.contents)
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { normalize } from 'path'
|
||||
import * as Bluebird from 'bluebird'
|
||||
import { Readable } from 'stream'
|
||||
import { createWriteStream, chmodSync } from 'fs'
|
||||
import { readFileAsync, dequote, isWindows } from './util'
|
||||
import { NexeCompiler } from './compiler'
|
||||
import { readFileAsync, dequote, isWindows } from '../util'
|
||||
import { NexeCompiler } from '../compiler'
|
||||
import { NexeTarget } from '../target'
|
||||
|
||||
function readStreamAsync(stream: NodeJS.ReadableStream): PromiseLike<string> {
|
||||
return new Bluebird(resolve => {
|
||||
return new Promise(resolve => {
|
||||
let input = ''
|
||||
stream.setEncoding('utf-8')
|
||||
stream.on('data', (x: string) => {
|
||||
@@ -56,10 +56,14 @@ export default async function cli(compiler: NexeCompiler, next: () => Promise<vo
|
||||
await next()
|
||||
}
|
||||
|
||||
compiler.output = output || `${compiler.options.name}${isWindows ? '.exe' : ''}`
|
||||
const deliverable = await compiler.compileAsync()
|
||||
compiler.output = isWindows
|
||||
? `${(output || compiler.options.name).replace(/\.exe$/, '')}.exe`
|
||||
: `${output || compiler.options.name}`
|
||||
|
||||
return new Bluebird((resolve, reject) => {
|
||||
const target = compiler.options.targets.shift() as NexeTarget
|
||||
const deliverable = await compiler.compileAsync(target)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const step = log.step('Writing result to file')
|
||||
deliverable
|
||||
.pipe(createWriteStream(normalize(compiler.output!)))
|
||||
@@ -1,8 +1,8 @@
|
||||
import download = require('download')
|
||||
import { isDirectoryAsync } from './util'
|
||||
import { LogStep } from './logger'
|
||||
import { isDirectoryAsync } from '../util'
|
||||
import { LogStep } from '../logger'
|
||||
import { IncomingMessage } from 'http'
|
||||
import { NexeCompiler } from './compiler'
|
||||
import { NexeCompiler } from '../compiler'
|
||||
|
||||
function fetchNodeSourceAsync(cwd: string, url: string, step: LogStep, options = {}) {
|
||||
const setText = (p: number) => step.modify(`Downloading Node: ${p.toFixed()}%...`)
|
||||
@@ -1,8 +1,7 @@
|
||||
import { each } from 'bluebird'
|
||||
import { readFileAsync, isDirectoryAsync } from './util'
|
||||
import { readFileAsync, isDirectoryAsync, each } from '../util'
|
||||
import { Buffer } from 'buffer'
|
||||
import * as globs from 'globby'
|
||||
import { NexeCompiler } from './compiler'
|
||||
import { NexeCompiler } from '../compiler'
|
||||
|
||||
export default async function resource(compiler: NexeCompiler, next: () => Promise<void>) {
|
||||
const resources = compiler.resources
|
||||
@@ -0,0 +1,86 @@
|
||||
export type NodePlatform = 'windows' | 'mac' | 'alpine' | 'linux'
|
||||
export type NodeArch = 'x86' | 'x64'
|
||||
|
||||
const platforms: NodePlatform[] = ['windows', 'mac', 'alpine', 'linux'],
|
||||
architectures: NodeArch[] = ['x86', 'x64']
|
||||
|
||||
export { platforms, architectures }
|
||||
|
||||
export interface NexeTarget {
|
||||
version: string
|
||||
platform: NodePlatform
|
||||
arch: NodeArch
|
||||
}
|
||||
|
||||
//TODO bsd
|
||||
const prettyPlatform: { [key: string]: NodePlatform } = {
|
||||
win32: 'windows',
|
||||
windows: 'windows',
|
||||
darwin: 'mac',
|
||||
macos: 'mac',
|
||||
mac: 'mac',
|
||||
linux: 'linux',
|
||||
static: 'alpine',
|
||||
alpine: 'alpine'
|
||||
}
|
||||
|
||||
//TODO arm
|
||||
const prettyArch: { [key: string]: NodeArch } = {
|
||||
x86: 'x86',
|
||||
ia32: 'x86',
|
||||
x32: 'x86',
|
||||
x64: 'x64'
|
||||
}
|
||||
|
||||
function isVersion(x: string) {
|
||||
if (!x) {
|
||||
return false
|
||||
}
|
||||
return /\d/.test(x.replace(/v|\./g, ''))
|
||||
}
|
||||
|
||||
function isPlatform(x: string): x is NodePlatform {
|
||||
return x in prettyPlatform
|
||||
}
|
||||
|
||||
function isArch(x: string): x is NodeArch {
|
||||
return x in prettyArch
|
||||
}
|
||||
|
||||
class Target implements NexeTarget {
|
||||
constructor(public arch: NodeArch, public platform: NodePlatform, public version: string) {}
|
||||
toJSON() {
|
||||
return this.toString()
|
||||
}
|
||||
toString() {
|
||||
return `${this.platform}-${this.arch}-${this.version}`
|
||||
}
|
||||
}
|
||||
|
||||
export function targetsEqual(a: NexeTarget, b: NexeTarget) {
|
||||
return a.arch === b.arch && a.platform === b.platform && a.version === b.version
|
||||
}
|
||||
|
||||
export function getTarget(target: string | NexeTarget = ''): NexeTarget {
|
||||
let arch = process.arch as NodeArch,
|
||||
platform = prettyPlatform[process.platform],
|
||||
version = process.version.slice(1)
|
||||
|
||||
if (typeof target !== 'string') {
|
||||
target = `${target.platform}-${target.arch}-${target.version}`
|
||||
}
|
||||
|
||||
target.toLowerCase().split('-').forEach(x => {
|
||||
if (isVersion(x)) {
|
||||
version = x
|
||||
}
|
||||
if (isPlatform(x)) {
|
||||
platform = prettyPlatform[x]
|
||||
}
|
||||
if (isArch(x)) {
|
||||
arch = prettyArch[x]
|
||||
}
|
||||
})
|
||||
|
||||
return new Target(arch, platform, version)
|
||||
}
|
||||
Vendored
+3
-19
@@ -1,23 +1,7 @@
|
||||
declare module 'nigel' {
|
||||
import { Writable } from 'stream'
|
||||
interface Needle {
|
||||
value: Buffer
|
||||
lastPos: number
|
||||
last: number
|
||||
length: number
|
||||
badCharShift: Buffer
|
||||
}
|
||||
|
||||
export function compile(needle: Buffer): Needle
|
||||
export function horspool(haystack: Buffer, needle: Needle, start: number): number
|
||||
export function all(haystack: Buffer, needle: Needle, pos: number): number[]
|
||||
export class Stream extends Writable {
|
||||
constructor(needle: Buffer)
|
||||
needle(needle: Buffer): void
|
||||
flush(): void
|
||||
}
|
||||
declare module 'got' {
|
||||
function got(url: string, options?: any): Promise<{ body: string }>
|
||||
export = got
|
||||
}
|
||||
|
||||
declare module 'download' {
|
||||
import { Duplex } from 'stream'
|
||||
interface DownloadOptions {
|
||||
|
||||
+30
-13
@@ -1,9 +1,26 @@
|
||||
import { readFile, writeFile, stat } from 'fs'
|
||||
import * as Bluebird from 'bluebird'
|
||||
import { execFile } from 'child_process'
|
||||
import pify = require('pify')
|
||||
import rimraf = require('rimraf')
|
||||
|
||||
const { promisify } = Bluebird
|
||||
const rimrafAsync = (promisify(rimraf) as any) as (path: string) => Bluebird<void>
|
||||
const rimrafAsync = pify(rimraf)
|
||||
|
||||
export async function each<T>(
|
||||
list: T[] | Promise<T[]>,
|
||||
action: (item: T, index: number, list: T[]) => Promise<any>
|
||||
) {
|
||||
const l = await list
|
||||
for (let i = 0; i < l.length; i++) {
|
||||
await action(l[i], i, l)
|
||||
}
|
||||
}
|
||||
|
||||
function falseOnEnoent(e: any) {
|
||||
if (e.code === 'ENOENT') {
|
||||
return false
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
function dequote(input: string) {
|
||||
input = input.trim()
|
||||
@@ -16,30 +33,30 @@ function dequote(input: string) {
|
||||
}
|
||||
|
||||
export interface ReadFileAsync {
|
||||
(path: string): Bluebird<Buffer>
|
||||
(path: string, encoding: string): Bluebird<string>
|
||||
(path: string): Promise<Buffer>
|
||||
(path: string, encoding: string): Promise<string>
|
||||
}
|
||||
|
||||
const readFileAsync = (promisify(readFile) as any) as ReadFileAsync
|
||||
const writeFileAsync = (promisify(writeFile) as any) as (
|
||||
path: string,
|
||||
contents: string | Buffer
|
||||
) => Promise<void>
|
||||
const statAsync = promisify(stat)
|
||||
const readFileAsync = pify(readFile)
|
||||
const writeFileAsync = pify(writeFile)
|
||||
const statAsync = pify(stat)
|
||||
const execFileAsync = pify(execFile)
|
||||
const isWindows = process.platform === 'win32'
|
||||
|
||||
function pathExistsAsync(path: string) {
|
||||
return statAsync(path).then(x => true).catch({ code: 'ENOENT' }, () => false)
|
||||
return statAsync(path).then(x => true).catch(falseOnEnoent)
|
||||
}
|
||||
|
||||
function isDirectoryAsync(path: string) {
|
||||
return statAsync(path).then(x => x.isDirectory()).catch({ code: 'ENOENT' }, () => false)
|
||||
return statAsync(path).then(x => x.isDirectory()).catch(falseOnEnoent)
|
||||
}
|
||||
|
||||
export {
|
||||
dequote,
|
||||
isWindows,
|
||||
rimrafAsync,
|
||||
statAsync,
|
||||
execFileAsync,
|
||||
readFileAsync,
|
||||
pathExistsAsync,
|
||||
isDirectoryAsync,
|
||||
|
||||
Reference in New Issue
Block a user