Compare commits

...

21 Commits

Author SHA1 Message Date
calebboyd d2756a5f75 fix: load implicit input if stdin is empty without a tty 2019-04-04 23:54:06 -05:00
calebboyd 255f3887c7 chore: remove unused methods 2019-04-04 19:37:30 -05:00
calebboyd 75ae41b7b9 chore: bump version 2019-04-04 09:48:17 -05:00
calebboyd 3692c142fb doc: describe mangle option 2019-04-04 09:47:20 -05:00
calebboyd af2e381ed4 feat: ensure output directory exists
closes #590
2019-04-04 09:35:15 -05:00
jerry_liu 44393a22da More flexiable nexe footer search range to fix digital sign binary launch issue
Fix #372
2019-04-03 13:37:31 -05:00
jerry_liu 57a08d2cfd remove compress option 2019-04-03 08:15:21 -05:00
calebboyd 6825cef609 feat: asset option 2019-04-03 08:12:26 -05:00
calebboyd b3c2d2e764 fix: use hardcoded version for asset url 2019-04-01 16:38:47 -05:00
calebboyd d73325ba35 chore: analyze resources as entrypoints 2019-03-30 20:18:41 -07:00
calebboyd 6e3cadbe22 chore: dep bump 2019-03-30 13:54:51 -07:00
calebboyd de42dd94ad refactor: run download for src and prebuilt before plugins or patches 2019-03-30 13:29:58 -07:00
calebboyd 37192e4ca8 fix: ignore node cli for 11.6.0+ 2019-03-28 19:19:03 -07:00
calebboyd c5cdbd9380 chore: remove unused directories in appveyor 2019-03-09 15:27:25 -06:00
calebboyd b022cd525d fix: size on bundled stat 2019-02-21 22:33:44 -06:00
bruce-one 72d9dfebf6 fix(fs): stat file and directories for bundled files (#589)
Ensure Stat return has correct prototype.
In particular to fix `Reflect.apply(Stats.prototype.isFile, stat, [])`.
2019-02-21 18:48:49 -06:00
calebboyd 8849ac0c0c chore: don't try to upload an existing asset 2019-01-31 19:56:36 -06:00
calebboyd 8ad6641278 chore: update travis vm 2019-01-31 17:54:10 -06:00
calebboyd 1a75bdb058 fix: avoid syncronous errors in compile method 2019-01-23 20:31:11 -06:00
calebboyd 12c77a34fd chore: update resolve-dependencies 2019-01-05 11:25:36 -06:00
calebboyd c76edb7c0b chore: expose build on compiler 2018-12-31 08:51:53 -06:00
23 changed files with 1095 additions and 408 deletions
+1 -2
View File
@@ -4,6 +4,5 @@ end_of_line = lf
charset = utf-8
indent_style = space
indent_size = 2
#https://github.com/Microsoft/vscode/issues/23983#event-1087502108
#trim_trailing_whitespace = true
trim_trailing_whitespace = true
insert_final_newline = true
+1
View File
@@ -1,6 +1,7 @@
.DS_Store
temp/
coverage
nexe
node_modules
*.log
*.exe
+1
View File
@@ -1,3 +1,4 @@
dist: xenial
language: node_js
node_js:
- '6'
+1 -1
View File
@@ -1,3 +1,3 @@
{
"recommendations": [ "eg2.tslint" ]
"recommendations": [ "ms-vscode.vscode-typescript-tslint-plugin" ]
}
+8 -1
View File
@@ -113,8 +113,15 @@ compile({
- #### `cwd: string`
- Directory nexe will operate on as though it is the cwd
- default: process.cwd()
- #### `mangle: boolean`
- If set to false, nexe will not include the virtual filesystem (your application and resources) on the output.
- This will cause the output to error as an "Invalid Binary" unless a userland patch alters the contents of lib/_third_party_main.js in the nodejs source.
- default: true
- #### `build: boolean`
- Build node from source, passing this flag tells nexe to download and build from source. Subsequently using this flag will cause nexe to use the previously built binary. To rebuild, first add [`--clean`](#clean-boolean)
- #### `asset: string`
- Provide a pre-built nexe binary asset, this can either be an http or https URL or a file path.
- default: `null`
- #### `python: string`
- On Linux this is the path pointing to your python2 executable
- On Windows this is the directory where `python` can be accessed
@@ -166,7 +173,7 @@ compile({
variable will still be processed. NODE_OPTIONS support can be disabled with the `--without-node-options` configure flag.
- default: `false`
- #### `fakeArgv: boolean`
- fake the entry point file name (`process.argv[1]`). If nexe was used with stdin this will be `'[stdin]'`.
- fake the entry point file name (`process.argv[1]`). If nexe was used with stdin this will be `'[stdin]'`.
- #### `ghToken: string`
- Provide a Github Token for accessing nexe releases
- This is usually needed in CI environments
+2
View File
@@ -9,6 +9,8 @@ environment:
GITHUB_TOKEN:
secure: 3wuEGJsppSKFvdwhp3jprUA9Zkc3WINlc/9oFXjhAR6J05lYMXP7Fl7lXTKpkGZx
install:
- rmdir C:\cygwin /s /q
- rmdir C:\QT /s /q
- ps: Install-Product node 8
- curl -L -o nasm.exe https://www.nasm.us/pub/nasm/releasebuilds/2.13.03/win64/nasm-2.13.03-installer-x64.exe
- start /wait nasm.exe /S
+14 -1
View File
@@ -10,7 +10,20 @@ if (require.main === module) {
process.stderr.write(showHelp ? options.help : options.version + eol)
} else {
const nexe = require('./lib/nexe')
nexe.compile(argv).catch(() => {
nexe.compile(argv).catch((error) => {
const NexeError = require('./lib/compiler').NexeError
const chalk = require('chalk')
const isSilent = Boolean(argv.silent === true || argv.loglevel === 'silent')
if (!isSilent) {
if (error instanceof NexeError) {
process.stderr.write(eol + chalk.red('Error: ') + error.message + eol
+ eol + 'See nexe -h for usage..' + eol + eol
)
} else {
process.stderr.write(error.stack + eol)
}
}
process.exit(1)
})
}
+855 -230
View File
File diff suppressed because it is too large Load Diff
+20 -19
View File
@@ -2,7 +2,7 @@
"name": "nexe",
"description": "Create a single executable out of your Node.js application",
"license": "MIT",
"version": "3.0.0-beta.12",
"version": "3.0.3",
"contributors": [
"Craig Condon <craig.j.condon@gmail.com> (http://crcn.io)",
"Jared Allard <jaredallard@outlook.com>",
@@ -36,40 +36,41 @@
"@calebboyd/semaphore": "^1.3.1",
"app-builder": "^5.2.0",
"caw": "^2.0.1",
"chalk": "^2.4.1",
"chalk": "^2.4.2",
"cherow": "1.6.9",
"download": "^7.1.0",
"globby": "^8.0.1",
"cherow": "1.6.8",
"got": "^9.5.0",
"globby": "^9.2.0",
"got": "^9.6.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"multistream": "^2.1.1",
"ora": "^3.0.0",
"ora": "^3.4.0",
"pify": "^4.0.1",
"resolve-dependencies": "^2.2.0",
"rimraf": "^2.6.2"
"resolve-dependencies": "^2.2.2",
"rimraf": "^2.6.3"
},
"devDependencies": {
"@types/chai": "^4.1.7",
"@types/download": "^6.2.4",
"@types/execa": "^0.9.0",
"@types/globby": "^8.0.0",
"@types/got": "^9.2.2",
"@types/globby": "^9.1.0",
"@types/got": "^9.4.1",
"@types/minimist": "^1.2.0",
"@types/mkdirp": "^0.5.2",
"@types/mocha": "^5.2.5",
"@types/mocha": "^5.2.6",
"@types/multistream": "^2.1.1",
"@types/ora": "^1.3.4",
"@types/ora": "^3.2.0",
"@types/pify": "3.0.2",
"@types/rimraf": "2.0.2",
"@types/semver": "^5.5.0",
"@types/semver": "^6.0.0",
"chai": "^4.2.0",
"execa": "^1.0.0",
"mocha": "^5.2.0",
"prettier": "^1.15.3",
"ts-node": "^7.0.1",
"tslint": "^5.12.0",
"tslint-config-prettier": "^1.17.0",
"mocha": "^6.0.2",
"prettier": "^1.16.4",
"ts-node": "^8.0.3",
"tslint": "^5.15.0",
"tslint-config-prettier": "^1.18.0",
"tslint-plugin-prettier": "^2.0.1",
"typescript": "^3.2.2"
"typescript": "^3.4.1"
}
}
+34 -55
View File
@@ -1,6 +1,6 @@
import { delimiter, dirname, normalize, join } from 'path'
import { delimiter, resolve, normalize, join } from 'path'
import { Buffer } from 'buffer'
import { createReadStream } from 'fs'
import { createReadStream, ReadStream } from 'fs'
import { spawn } from 'child_process'
import { Logger, LogStep } from './logger'
import {
@@ -15,9 +15,6 @@ import {
} from './util'
import { NexeOptions, version } from './options'
import { NexeTarget } from './target'
import download = require('download')
import { getLatestGitRelease } from './releases'
import { IncomingMessage } from 'http'
import combineStreams = require('multistream')
import { Bundle, toStream } from './fs/bundle'
@@ -35,22 +32,28 @@ export interface NexeFile {
export { NexeOptions }
export class NexeError extends Error {
constructor(m: string) {
super(m)
Object.setPrototypeOf(this, NexeError.prototype)
}
}
export class NexeCompiler {
/**
* Epoch of when compilation started
*/
private start = Date.now()
private compileStep: LogStep | undefined
public log = new Logger(this.options.loglevel)
/**
* Copy of process.env
*/
private env = { ...process.env }
public env = { ...process.env }
/**
* Virtual FileSystem
*/
private bundle: Bundle
private compileStep: LogStep | undefined
public log = new Logger(this.options.loglevel)
public bundle: Bundle
/**
* Root directory for the source of the current build
*/
@@ -94,12 +97,23 @@ export class NexeCompiler {
/**
* The file path of node binary
*/
private nodeSrcBinPath: string
public nodeSrcBinPath: string
/**
* Remote asset path if available
*/
public remoteAsset: string
constructor(public options: NexeOptions) {
const { python } = (this.options = options)
//SOMEDAY iterate over multiple targets with `--outDir`
this.targets = options.targets as NexeTarget[]
this.target = this.targets[0]
if (options.asset && options.asset.startsWith('http')) {
this.remoteAsset = options.asset
} else {
this.remoteAsset =
'https://github.com/nexe/nexe/releases/download/v3.0.0/' + this.target.toString()
}
this.src = join(this.options.temp, this.target.version)
this.configureScript = configure + (semverGt(this.target.version, '10.10.0') ? '.py' : '')
this.nodeSrcBinPath = isWindows
@@ -179,11 +193,14 @@ export class NexeCompiler {
assertBuild() {
if (!this.options.build) {
throw new Error('This feature is only available with `--build`')
throw new NexeError('This feature is only available with `--build`')
}
}
public getNodeExecutableLocation(target?: NexeTarget) {
if (this.options.asset && !this.options.asset.startsWith('http')) {
return resolve(this.options.cwd, this.options.asset)
}
if (target) {
return join(this.options.temp, target.toString())
}
@@ -212,7 +229,7 @@ export class NexeCompiler {
}
if (code != 0) {
const error = `${command} ${args.join(' ')} exited with code: ${code}`
reject(new Error(error))
reject(new NexeError(error))
}
resolve()
})
@@ -226,7 +243,7 @@ export class NexeCompiler {
])
}
private async _buildAsync() {
public async build(): Promise<ReadStream> {
this.compileStep!.log(
`Configuring node build${
this.options.configure.length ? ': ' + this.options.configure : '...'
@@ -241,44 +258,11 @@ export class NexeCompiler {
return createReadStream(this.getNodeExecutableLocation())
}
private async _fetchPrebuiltBinaryAsync(target: NexeTarget) {
let downloadOptions = this.options.downloadOptions
if (this.options.ghToken) {
downloadOptions = Object.assign({}, downloadOptions)
downloadOptions.headers = Object.assign({}, downloadOptions.headers, {
Authorization: 'token ' + this.options.ghToken
})
}
const githubRelease = await getLatestGitRelease(downloadOptions)
const assetName = target.toString()
const asset = githubRelease.assets.find(x => x.name === assetName)
if (!asset) {
throw new Error(`${assetName} not available, create it using the --build flag`)
}
const filename = this.getNodeExecutableLocation(target)
await download(asset.browser_download_url, dirname(filename), this.options.downloadOptions).on(
'response',
(res: IncomingMessage) => {
const total = +res.headers['content-length']!
let current = 0
res.on('data', data => {
current += data.length
this.compileStep!.modify(`Downloading...${((current / total) * 100).toFixed()}%`)
})
}
)
return createReadStream(filename)
}
private async _shouldCompileBinaryAsync(
binary: NodeJS.ReadableStream | null,
location: string | undefined
) {
//TODO combine make/configure/vcBuild/and modified times of included files
//SOMEDAY combine make/configure/vcBuild/and modified times of included files
const { snapshot, build } = this.options
if (!binary) {
@@ -288,8 +272,6 @@ export class NexeCompiler {
if (build && snapshot != null && (await pathExistsAsync(snapshot))) {
const snapshotLastModified = (await statAsync(snapshot)).mtimeMs
const binaryLastModified = (await statAsync(location)).mtimeMs
// if build was requested and there's a snapshot to embed in the binary,
// we need to rebuild if the snapshot was just modified.
return snapshotLastModified > binaryLastModified
}
@@ -301,12 +283,9 @@ export class NexeCompiler {
const build = this.options.build
const location = this.getNodeExecutableLocation(build ? undefined : target)
let binary = (await pathExistsAsync(location)) ? createReadStream(location) : null
if (!build && !binary) {
step.modify('Fetching prebuilt binary')
binary = await this._fetchPrebuiltBinaryAsync(target)
}
if (await this._shouldCompileBinaryAsync(binary, location)) {
binary = await this._buildAsync()
binary = await this.build()
step.log('Node binary compiled')
}
return this._assembleDeliverable(binary!)
+7 -12
View File
@@ -37,11 +37,7 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
notAFile = '!@#$%^&*',
isWin = process.platform.startsWith('win'),
isString = (x: any): x is string => typeof x === 'string' || x instanceof String,
isNotFile = () => false,
isNotDirectory = isNotFile,
isFile = () => true,
noop = () => {},
isDirectory = isFile,
path = require('path')
let log = (text: string) => true
@@ -85,22 +81,21 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
}
}
const createStat = function(directoryExtensions: any, fileExtensions?: any) {
if (!fileExtensions) {
return Object.assign({}, binary.layout.stat, directoryExtensions, { size: 0 }, statTime())
}
const size = directoryExtensions[1]
return Object.assign({}, binary.layout.stat, fileExtensions, { size }, statTime())
const createStat = function(extensions: any) {
return Object.assign(new fs.Stats(), binary.layout.stat, statTime(), extensions)
}
const ownStat = function(filepath: any) {
setupManifest()
const key = getKey(filepath)
if (directories[key]) {
return createStat({ isDirectory, isFile: isNotFile })
let mode = binary.layout.stat.mode
mode |= fs.constants.S_IFDIR
mode &= ~fs.constants.S_IFREG
return createStat({ mode, size: 0 })
}
if (manifest[key]) {
return createStat(manifest[key], { isFile, isDirectory: isNotDirectory })
return createStat({ size: manifest[key][1] })
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
import colors = require('chalk')
import ora = require('ora')
import colors from 'chalk'
import ora from 'ora'
const frameLength = 120
+17 -19
View File
@@ -1,6 +1,6 @@
import { EOL } from 'os'
import { compose } from 'app-builder'
import { NexeCompiler } from './compiler'
import { NexeCompiler, NexeError } from './compiler'
import { normalizeOptions, NexeOptions, NexePatch } from './options'
import resource from './steps/resource'
import clean from './steps/clean'
@@ -15,31 +15,29 @@ async function compile(
compilerOptions?: Partial<NexeOptions>,
callback?: (err: Error | null) => void
) {
const options = normalizeOptions(compilerOptions)
const compiler = new NexeCompiler(options)
let error = null,
options: NexeOptions | null = null,
compiler: NexeCompiler | null = null
const nexe = compose(
clean,
resource,
cli,
bundle,
shim,
options.build ? [download, artifacts, ...patches, ...(options.patches as NexePatch[])] : [],
options.plugins as NexePatch[]
)
let error = null
try {
await nexe(compiler)
options = normalizeOptions(compilerOptions)
compiler = new NexeCompiler(options)
await compose(
clean,
resource,
cli,
bundle,
shim,
download,
options.build ? [artifacts, ...patches, ...(options.patches as NexePatch[])] : [],
options.plugins as NexePatch[]
)(compiler)
} catch (e) {
error = e
}
if (error) {
compiler.quit(error)
if (compiler.options.loglevel !== 'silent' && error) {
process.stderr.write(EOL + error.message + EOL)
}
compiler && compiler.quit(error)
if (callback) return callback(error)
return Promise.reject(error)
}
+23 -22
View File
@@ -1,5 +1,5 @@
import * as parseArgv from 'minimist'
import { NexeCompiler } from './compiler'
import { NexeCompiler, NexeError } from './compiler'
import { isWindows, STDIN_FLAG } from './util'
import { basename, extname, join, isAbsolute, resolve } from 'path'
import { getTarget, NexeTarget } from './target'
@@ -21,6 +21,7 @@ export interface NexeOptions {
output: string
targets: (string | NexeTarget)[]
name: string
asset: string
cwd: string
flags: string[]
configure: string[]
@@ -35,11 +36,6 @@ export interface NexeOptions {
patches: (string | NexePatch)[]
plugins: (string | NexePatch)[]
native: any
/**
* @deprecated
* Use mangle: false instead
*/
empty: boolean
mangle: boolean
ghToken: string
sourceUrl?: string
@@ -53,7 +49,6 @@ export interface NexeOptions {
ico?: string
debugBundle?: boolean
warmup?: string
compress?: boolean
clean?: boolean
/**
* Api Only
@@ -65,11 +60,11 @@ const defaults = {
flags: [],
cwd: process.cwd(),
configure: [],
mangle: true,
make: [],
targets: [],
vcBuild: isWindows ? ['nosign', 'release'] : [],
enableNodeCli: false,
compress: false,
build: false,
bundle: true,
patches: [],
@@ -104,6 +99,7 @@ ${c.bold('nexe <entry-file> [options]')}
-t --target -- node version description
-n --name -- main app module name
-r --resource -- *embed files (glob) within the binary
-a --asset -- alternate asset path, file or url pointing to a base (nexe) binary
--plugin -- extend nexe runtime behavior
${c.underline.bold('Building from source:')}
@@ -113,7 +109,8 @@ ${c.bold('nexe <entry-file> [options]')}
-f --flag -- *v8 flags to include during compilation
-c --configure -- *arguments to the configure step
-m --make -- *arguments to the make/build step
--no-mangle -- used when generating base binaries, or when pathing _third_party_main manually.
--patch -- module with middelware default export for adding a build patch
--no-mangle -- used when generating base binaries, or when patching _third_party_main manually.
--snapshot -- path to a warmup snapshot
--ico -- file name for alternate icon file (windows)
--rc-* -- populate rc file options (windows)
@@ -165,7 +162,7 @@ function extractLogLevel(options: NexeOptions) {
}
function isName(name: string) {
return name && name !== 'index'
return name && name !== 'index' && name !== STDIN_FLAG
}
function extractName(options: NexeOptions) {
@@ -222,7 +219,7 @@ export function resolveEntry(
result = resolveFileNameSync(cwd, '.')
}
if (!result.absPath) {
throw new Error(`Entry file "${input}" not found!`)
throw new NexeError(`Entry file "${input || ''}" not found!`)
}
return result.absPath
}
@@ -268,6 +265,21 @@ function normalizeOptions(input?: Partial<NexeOptions>): NexeOptions {
: `${options.output || options.name}`
options.output = resolve(cwd, options.output)
const requireDefault = (x: string) => {
if (typeof x === 'string') {
return require(x).default
}
return x
}
options.mangle = 'mangle' in opts ? opts.mangle : true
options.plugins = flatten(opts.plugin, options.plugins).map(requireDefault)
options.patches = flatten(opts.patch, options.patches).map(requireDefault)
if ((!options.mangle && !options.bundle) || options.patches.length) {
options.build = true
}
if (options.build) {
const { arch } = options.targets[0] as NexeTarget
if (isWindows) {
@@ -277,17 +289,6 @@ function normalizeOptions(input?: Partial<NexeOptions>): NexeOptions {
}
}
const requireDefault = (x: string) => {
if (typeof x === 'string') {
return require(x).default
}
return x
}
options.mangle = 'mangle' in opts ? opts.mangle : !opts.empty
options.plugins = flatten(opts.plugin, options.plugins).map(requireDefault)
options.patches = flatten(opts.patch, options.patches).map(requireDefault)
Object.keys(alias)
.filter(k => k !== 'rc')
.forEach(x => delete opts[x])
+8 -5
View File
@@ -1,17 +1,20 @@
const fs = require('fs'),
fd = fs.openSync(process.execPath, 'r'),
stat = fs.statSync(process.execPath),
footer = Buffer.alloc(32, 0)
tailSize = Math.min(stat.size, 16000),
tailWindow = Buffer.from(Array(tailSize))
fs.readSync(fd, footer, 0, 32, stat.size - 32)
fs.readSync(fd, tailWindow, 0, tailSize, stat.size - tailSize)
if (!footer.slice(0, 16).equals(Buffer.from('<nexe~~sentinel>'))) {
const footerPosition = tailWindow.indexOf('<nexe~~sentinel>')
if (footerPosition == -1) {
throw 'Invalid Nexe binary'
}
const contentSize = footer.readDoubleLE(16),
const footer = tailWindow.slice(footerPosition, footerPosition + 32),
contentSize = footer.readDoubleLE(16),
resourceSize = footer.readDoubleLE(24),
contentStart = stat.size - 32 - resourceSize - contentSize,
contentStart = stat.size - tailSize + footerPosition - resourceSize - contentSize,
resourceStart = contentStart + contentSize
Object.defineProperty(
+7 -1
View File
@@ -6,7 +6,13 @@ export default async function disableNodeCli(compiler: NexeCompiler, next: () =>
return next()
}
if (semverGt(compiler.target.version, '10.9')) {
if (semverGt(compiler.target.version, '11.6.0')) {
await compiler.replaceInFileAsync(
'src/node.cc',
/(?<!int )ProcessGlobalArgs\(/g,
'0;//ProcessGlobalArgs('
)
} else if (semverGt(compiler.target.version, '10.9')) {
await compiler.replaceInFileAsync('src/node.cc', /(?<!void )ProcessArgv\(/g, '//ProcessArgv(')
} else if (semverGt(compiler.target.version, '9.999')) {
await compiler.replaceInFileAsync(
+20 -8
View File
@@ -1,7 +1,7 @@
import { NexeCompiler } from '../compiler'
import { NexeCompiler, NexeError } from '../compiler'
import { resolve, relative } from 'path'
import { each } from '@calebboyd/semaphore'
import resolveFiles from 'resolve-dependencies'
import resolveFiles, { resolveFileNameSync } from 'resolve-dependencies'
import { dequote, STDIN_FLAG } from '../util'
import { Readable } from 'stream'
@@ -16,12 +16,13 @@ function getStdIn(stdin: Readable): Promise<string> {
out += current
}
})
.on('end', () => resolve(out))
.on('end', () => resolve(out.trim()))
})
}
export default async function bundle(compiler: NexeCompiler, next: any) {
const { bundle, cwd, input } = compiler.options
const { bundle, cwd, input: inputPath } = compiler.options
let input = inputPath
compiler.entrypoint = './' + relative(cwd, input)
compiler.startup = ';require("module").runMain();'
@@ -35,20 +36,31 @@ export default async function bundle(compiler: NexeCompiler, next: any) {
code = await require(bundle).createBundle(compiler.options)
}
if (input === STDIN_FLAG) {
if (input === STDIN_FLAG && (code = code || dequote(await getStdIn(process.stdin)))) {
compiler.stdinUsed = true
compiler.entrypoint = './__nexe_stdin.js'
code = code || dequote(await getStdIn(process.stdin))
await compiler.addResource(resolve(cwd, compiler.entrypoint), code)
return next()
}
const { files, warnings } = await resolveFiles(input, { cwd, expand: true, loadContent: false })
if (input === STDIN_FLAG) {
const maybeInput = resolveFileNameSync(cwd, '.')
if (!maybeInput) {
throw new NexeError('No valid input detected')
}
input = maybeInput.absPath
}
const { files, warnings } = await resolveFiles(
input,
...Object.keys(compiler.bundle.index).filter(x => x.endsWith('.js')),
{ cwd, expand: true, loadContent: false }
)
if (
warnings.filter(x => x.startsWith('Error parsing file') && !x.includes('node_modules')).length
) {
throw new Error('Parsing Error:\n' + warnings.join('\n'))
throw new NexeError('Parsing Error:\n' + warnings.join('\n'))
}
await each(Object.keys(files), (filename: string) => compiler.addResource(filename), {
+20 -11
View File
@@ -1,8 +1,9 @@
import { normalize, relative } from 'path'
import { dirname, normalize, relative } from 'path'
import { createWriteStream, chmodSync, statSync } from 'fs'
import { NexeCompiler } from '../compiler'
import { NexeTarget } from '../target'
import { STDIN_FLAG } from '../util'
import mkdirp = require('mkdirp')
/**
* The "cli" step detects the appropriate input. If no input options are passed,
@@ -16,28 +17,36 @@ import { STDIN_FLAG } from '../util'
*/
export default async function cli(compiler: NexeCompiler, next: () => Promise<void>) {
await next()
const { log } = compiler
const target = compiler.options.targets.shift() as NexeTarget
const deliverable = await compiler.compileAsync(target)
const { log } = compiler,
target = compiler.options.targets.shift() as NexeTarget,
deliverable = await compiler.compileAsync(target),
output = normalize(compiler.output!)
mkdirp.sync(dirname(output))
return new Promise((resolve, reject) => {
const step = log.step('Writing result to file')
deliverable
.pipe(createWriteStream(normalize(compiler.output!)))
.pipe(createWriteStream(output))
.on('error', reject)
.once('close', (e: Error) => {
if (e) {
reject(e)
} else if (compiler.output) {
const output = compiler.output
const mode = statSync(output).mode | 0o111
const output = compiler.output,
mode = statSync(output).mode | 0o111,
inputFileLogOutput = relative(process.cwd(), compiler.options.input),
outputFileLogOutput = relative(process.cwd(), output)
chmodSync(output, mode.toString(8).slice(-3))
const inputFile = relative(process.cwd(), compiler.options.input)
const outputFile = relative(process.cwd(), output)
step.log(
`Entry: '${
compiler.stdinUsed ? (compiler.options.mangle ? STDIN_FLAG : '[none]') : inputFile
}' written to: ${outputFile}`
compiler.stdinUsed
? compiler.options.mangle
? STDIN_FLAG
: '[none]'
: inputFileLogOutput
}' written to: ${outputFileLogOutput}`
)
resolve(compiler.quit())
}
+42 -12
View File
@@ -2,7 +2,8 @@ import download = require('download')
import { pathExistsAsync } from '../util'
import { LogStep } from '../logger'
import { IncomingMessage } from 'http'
import { NexeCompiler } from '../compiler'
import { NexeCompiler, NexeError } from '../compiler'
import { dirname } from 'path'
function fetchNodeSourceAsync(dest: string, url: string, step: LogStep, options = {}) {
const setText = (p: number) => step.modify(`Downloading Node: ${p.toFixed()}%...`)
@@ -21,27 +22,56 @@ function fetchNodeSourceAsync(dest: string, url: string, step: LogStep, options
.then(() => step.log(`Node source extracted to: ${dest}`))
}
async function fetchPrebuiltBinary(compiler: NexeCompiler, step: any) {
const { target, remoteAsset } = compiler,
filename = compiler.getNodeExecutableLocation(target)
try {
await download(remoteAsset, dirname(filename), compiler.options.downloadOptions).on(
'response',
(res: IncomingMessage) => {
const total = +res.headers['content-length']!
let current = 0
res.on('data', data => {
current += data.length
step!.modify(`Downloading...${((current / total) * 100).toFixed()}%`)
})
}
)
} catch (e) {
if (e.statusCode === 404) {
throw new NexeError(`${remoteAsset} is not available, create it using the --build flag`)
} else {
throw new NexeError('Error downloading prebuilt binary: ' + e)
}
}
}
/**
* Downloads the node source to the configured temporary directory
* @param {*} compiler
* @param {*} next
*/
export default async function downloadNode(compiler: NexeCompiler, next: () => Promise<void>) {
const {
src,
log,
targets: [{ version }]
} = compiler
const { sourceUrl, downloadOptions } = compiler.options
const url = sourceUrl || `https://nodejs.org/dist/v${version}/node-v${version}.tar.gz`
const step = log.step(`Downloading Node.js source from: ${url}`)
if (await pathExistsAsync(src)) {
step.log('Source already downloaded')
const { src, log, target } = compiler,
{ version } = target,
{ sourceUrl, downloadOptions, build } = compiler.options,
url = sourceUrl || `https://nodejs.org/dist/v${version}/node-v${version}.tar.gz`,
step = log.step(
`Downloading ${build ? '' : 'pre-built '}Node.js${build ? `source from: ${url}` : ''}`
),
exeLocation = compiler.getNodeExecutableLocation(build ? undefined : target),
downloadExists = await pathExistsAsync(build ? src : exeLocation)
if (downloadExists) {
step.log('Already downloaded...')
return next()
}
if (compiler.options.build) {
if (build) {
await fetchNodeSourceAsync(src, url, step, downloadOptions)
} else {
await fetchPrebuiltBinary(compiler, step)
}
return next()
+1 -1
View File
@@ -1,5 +1,5 @@
import { isDirectoryAsync, each } from '../util'
import * as globs from 'globby'
import globs from 'globby'
import { NexeCompiler } from '../compiler'
export default async function resource(compiler: NexeCompiler, next: () => Promise<any>) {
+6 -1
View File
@@ -2,7 +2,7 @@ import * as nexe from '../lib/nexe'
import { getUnBuiltReleases, getLatestGitRelease } from '../lib/releases'
import * as ci from './ci'
import { runDockerBuild } from './docker'
import { getTarget } from '../lib/target'
import { getTarget, targetsEqual } from '../lib/target'
import { pathExistsAsync, readFileAsync, execFileAsync } from '../lib/util'
import got = require('got')
@@ -70,6 +70,11 @@ async function build() {
if (await pathExistsAsync(output)) {
await assertNexeBinary(output)
const gitRelease = await getLatestGitRelease({ headers })
const unbuiltReleases = await getUnBuiltReleases({ headers })
if (!unbuiltReleases.some(x => targetsEqual(x, target))) {
console.log(`${target} already uploaded.`)
return
}
await got(gitRelease.upload_url.split('{')[0], {
query: { name: target.toString() },
body: await readFileAsync(output),
+4 -4
View File
@@ -9,7 +9,7 @@ function alpine(target: NexeTarget) {
FROM ${target.arch === 'x64' ? '' : 'i386/'}alpine:3.4
RUN apk add --no-cache curl make gcc g++ binutils-gold python linux-headers paxctl libgcc libstdc++ git vim tar gzip wget
ENV NODE_VERSION=${target.version}
ENV NEXE_VERSION=beta
ENV NEXE_VERSION=latest
WORKDIR /
RUN curl -sSL https://nodejs.org/dist/v\${NODE_VERSION}/node-v\${NODE_VERSION}.tar.gz | tar -xz && \
@@ -21,18 +21,18 @@ RUN curl -sSL https://nodejs.org/dist/v\${NODE_VERSION}/node-v\${NODE_VERSION}.t
RUN rm /nexe_temp/\${NODE_VERSION}/out/Release/node && \
npm install -g nexe@\${NEXE_VERSION} && \
nexe --build --empty --temp /nexe_temp -c="--fully-static" -o out --enableStdIn=false
nexe --build --no-mangle --temp /nexe_temp -c="--fully-static" -o out --enableStdIn=false
`.trim()
}
function arm(target: NexeTarget) {
return `
FROM hypriot/rpi-node
ENV NEXE_VERSION=beta
ENV NEXE_VERSION=latest
WORKDIR /
RUN yarn global add nexe@\${NEXE_VERSION} && \
nexe --build --empty -o out -t ${target.version}
nexe --build --no-mangle -o out -t ${target.version}
`.trim()
}
+1 -1
View File
@@ -3,7 +3,7 @@
"target":"es5",
"skipLibCheck": true,
"experimentalDecorators": true,
"lib": ["es2017"],
"lib": ["es2018"],
"module": "commonjs",
"outDir": "./lib",
"strict": true