Compare commits
30 Commits
v3.0.0-beta.9
...
v3.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
| c9c9b5a0a3 | |||
| d2756a5f75 | |||
| 255f3887c7 | |||
| 75ae41b7b9 | |||
| 3692c142fb | |||
| af2e381ed4 | |||
| 44393a22da | |||
| 57a08d2cfd | |||
| 6825cef609 | |||
| b3c2d2e764 | |||
| d73325ba35 | |||
| 6e3cadbe22 | |||
| de42dd94ad | |||
| 37192e4ca8 | |||
| c5cdbd9380 | |||
| b022cd525d | |||
| 72d9dfebf6 | |||
| 8849ac0c0c | |||
| 8ad6641278 | |||
| 1a75bdb058 | |||
| 12c77a34fd | |||
| c76edb7c0b | |||
| 09d7093295 | |||
| 3a091f45bd | |||
| 9575c0811b | |||
| ab6b540e23 | |||
| dcea374922 | |||
| b3b6c6b936 | |||
| 058c34ee8a | |||
| 9750c70873 |
+1
-1
@@ -5,4 +5,4 @@ export NVS_HOME="$HOME/.nvs"
|
||||
|
||||
set -e -x
|
||||
|
||||
yarn run asset-compile
|
||||
npm run asset-compile
|
||||
|
||||
@@ -8,13 +8,13 @@ jobs:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- package-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||
- package-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}
|
||||
- package- # Fallback for the latest package.json cache
|
||||
- run:
|
||||
name: setup
|
||||
command: .circleci/setup.sh
|
||||
- save_cache:
|
||||
key: package-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
|
||||
key: package-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}
|
||||
paths:
|
||||
- node_modules
|
||||
- run:
|
||||
|
||||
+3
-4
@@ -1,11 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
echo "setting up node to use latest lts"
|
||||
|
||||
export NVS_HOME="$HOME/.nvs"
|
||||
git clone --depth=1 https://github.com/jasongin/nvs "$NVS_HOME"
|
||||
. "$NVS_HOME/nvs.sh" install
|
||||
nvs add lts && nvs link lts nvs use default
|
||||
npm install -g yarn
|
||||
yarn
|
||||
node -v
|
||||
npm -v
|
||||
npm i
|
||||
|
||||
+1
-2
@@ -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,6 +1,7 @@
|
||||
.DS_Store
|
||||
temp/
|
||||
coverage
|
||||
nexe
|
||||
node_modules
|
||||
*.log
|
||||
*.exe
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
dist: xenial
|
||||
language: node_js
|
||||
node_js:
|
||||
- '6'
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"recommendations": [ "eg2.tslint" ]
|
||||
"recommendations": [ "ms-vscode.vscode-typescript-tslint-plugin" ]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<a href="https://www.npmjs.com/package/nexe"><img src="https://img.shields.io/npm/dt/nexe.svg" alt="Downloads"></a>
|
||||
<a href="https://www.npmjs.com/package/nexe"><img src="https://img.shields.io/npm/v/nexe.svg" alt="Version"></a>
|
||||
<a href="https://www.npmjs.com/package/nexe"><img src="https://img.shields.io/npm/l/nexe.svg" alt="License"></a>
|
||||
<a href="https://gitter.im/nexe/nexe?utm_source=badge&utm_medium=badge"><img src="https://badges.gitter.im/nexe/nexe.svg"></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><code>npm i nexe -g</code></p>
|
||||
@@ -43,7 +42,6 @@ For more CLI options see: `nexe --help`
|
||||
### Examples
|
||||
|
||||
- `nexe server.js -r "public/**/*.html"`
|
||||
- `nexe my-bundle.js --no-bundle -o app.exe`
|
||||
- `nexe --build`
|
||||
- `nexe -t x86-8.0.0`
|
||||
|
||||
@@ -90,14 +88,14 @@ compile({
|
||||
- Output executable file path
|
||||
- default: same as `name` with an OS specific extension.
|
||||
- #### `target: string | object`
|
||||
- An object or string describing platform-arch-version. e.g. `'windows-ia32-6.10.3'`
|
||||
- An object or string describing platform-arch-version. e.g. `'windows-ia32-10.13.0'`
|
||||
- each segment is optional, and will be merged with the current environment
|
||||
- Examples: ([full list](https://github.com/nexe/nexe/releases))
|
||||
- `'win32-x86-8.6.0`
|
||||
- `'win32-x86-10.13.0`
|
||||
- `{ platform: 'alpine' }`
|
||||
- `darwin-8.6.0`
|
||||
- `darwin-10.13.0`
|
||||
- `linux-x64`
|
||||
- `macos-8.4.0`
|
||||
- `macos-10.13.0`
|
||||
|
||||
See [test/target.spec.ts](test/target.spec.ts)
|
||||
- If the [`build`](#build-boolean) flag is set, the platform portion of the target is ignored.
|
||||
@@ -115,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
|
||||
@@ -145,12 +150,12 @@ compile({
|
||||
- #### `temp: string`
|
||||
- Path to use for storing nexe's build files
|
||||
- Override in the env with `NEXE_TEMP`
|
||||
- default: `./.nexe` in the cwd
|
||||
- default: `~/.nexe`
|
||||
- #### `ico: string`
|
||||
- Path to a user provided icon to be used (Windows only). Requires `--build` to be set.
|
||||
- #### `rc: object`
|
||||
- Settings for patching the [node.rc](https://github.com/nodejs/node/blob/master/src/res/node.rc) configuration file (Windows only).
|
||||
- Example:
|
||||
- Example (keys may vary depending ont the version. Reference the file linked above):
|
||||
```javascript
|
||||
{
|
||||
CompanyName: "ACME Corp",
|
||||
@@ -168,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Generated
+860
-243
File diff suppressed because it is too large
Load Diff
+20
-19
@@ -2,7 +2,7 @@
|
||||
"name": "nexe",
|
||||
"description": "Create a single executable out of your Node.js application",
|
||||
"license": "MIT",
|
||||
"version": "3.0.0-beta.9",
|
||||
"version": "3.0.4",
|
||||
"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",
|
||||
"cherow": "^1.6.8",
|
||||
"chalk": "^2.4.2",
|
||||
"cherow": "1.6.9",
|
||||
"download": "^7.1.0",
|
||||
"globby": "^8.0.1",
|
||||
"got": "^9.3.2",
|
||||
"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.0",
|
||||
"@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.2",
|
||||
"ts-node": "^7.0.1",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-config-prettier": "^1.16.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.1.6"
|
||||
"typescript": "^3.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
+44
-60
@@ -1,7 +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 { Readable, Stream } from 'stream'
|
||||
import { createReadStream, ReadStream } from 'fs'
|
||||
import { spawn } from 'child_process'
|
||||
import { Logger, LogStep } from './logger'
|
||||
import {
|
||||
@@ -16,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'
|
||||
|
||||
@@ -26,6 +22,8 @@ const isBsd = Boolean(~process.platform.indexOf('bsd'))
|
||||
const make = isWindows ? 'vcbuild.bat' : isBsd ? 'gmake' : 'make'
|
||||
const configure = isWindows ? 'configure' : './configure'
|
||||
|
||||
type StringReplacer = (match: string) => string
|
||||
|
||||
export interface NexeFile {
|
||||
filename: string
|
||||
absPath: string
|
||||
@@ -34,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
|
||||
*/
|
||||
@@ -82,6 +86,10 @@ export class NexeCompiler {
|
||||
* Output filename (-o myapp.exe)
|
||||
*/
|
||||
public output = this.options.output
|
||||
/**
|
||||
* Flag to indicate whether or notstdin was used for input
|
||||
*/
|
||||
public stdinUsed = false
|
||||
/**
|
||||
* Path to the configure script
|
||||
*/
|
||||
@@ -89,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
|
||||
@@ -155,9 +174,9 @@ export class NexeCompiler {
|
||||
}
|
||||
|
||||
@bound
|
||||
async replaceInFileAsync(file: string, replace: string | RegExp, value: string) {
|
||||
async replaceInFileAsync(file: string, replace: string | RegExp, value: string | StringReplacer) {
|
||||
const entry = await this.readFileAsync(file)
|
||||
entry.contents = entry.contents.replace(replace, value)
|
||||
entry.contents = entry.contents.replace(replace, value as any)
|
||||
}
|
||||
|
||||
@bound
|
||||
@@ -166,19 +185,22 @@ export class NexeCompiler {
|
||||
entry.contents = contents
|
||||
}
|
||||
|
||||
quit() {
|
||||
quit(error?: any) {
|
||||
const time = Date.now() - this.start
|
||||
this.log.write(`Finished in ${time / 1000}s`)
|
||||
this.log.write(`Finished in ${time / 1000}s`, error ? 'red' : 'green')
|
||||
return this.log.flush()
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
@@ -207,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()
|
||||
})
|
||||
@@ -221,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 : '...'
|
||||
@@ -236,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) {
|
||||
@@ -283,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
|
||||
}
|
||||
|
||||
@@ -296,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!)
|
||||
|
||||
+48
-53
@@ -31,34 +31,35 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
}
|
||||
originalFsMethods = Object.assign({}, fs)
|
||||
nexeBinary = binary
|
||||
const { blobPath, resources: manifest } = binary
|
||||
const { resourceStart, stat } = binary.layout
|
||||
const directories: { [key: string]: { [key: string]: boolean } } = {},
|
||||
const { blobPath, resources: manifest } = binary,
|
||||
{ resourceStart, stat } = binary.layout,
|
||||
directories: { [key: string]: { [key: string]: boolean } } = {},
|
||||
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')
|
||||
path = require('path'),
|
||||
baseDir = path.dirname(process.execPath)
|
||||
|
||||
let log = (text: string) => {
|
||||
if ((process.env.DEBUG || '').toLowerCase().includes('nexe:require')) {
|
||||
process.stderr.write('[nexe] - ' + text + '\n')
|
||||
} else {
|
||||
log = noop
|
||||
}
|
||||
let log = (text: string) => true
|
||||
if ((process.env.DEBUG || '').toLowerCase().includes('nexe:require')) {
|
||||
log = (text: string) => process.stderr.write('[nexe] - ' + text + '\n')
|
||||
}
|
||||
|
||||
const getKey = process.platform.startsWith('win')
|
||||
? function getKey(filepath: string): string {
|
||||
let key = path.resolve(filepath)
|
||||
if (key.substr(1, 2) === ':\\') {
|
||||
key = key[0].toUpperCase() + key.substr(1)
|
||||
}
|
||||
return key
|
||||
}
|
||||
: path.resolve
|
||||
const getKey = function getKey(filepath: string | Buffer | null): string {
|
||||
if (Buffer.isBuffer(filepath)) {
|
||||
filepath = filepath.toString()
|
||||
}
|
||||
if (!isString(filepath)) {
|
||||
return notAFile
|
||||
}
|
||||
let key = path.resolve(baseDir, filepath)
|
||||
|
||||
if (isWin && key.substr(1, 2) === ':\\') {
|
||||
key = key[0].toUpperCase() + key.substr(1)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
const statTime = function() {
|
||||
return {
|
||||
@@ -81,22 +82,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: string) {
|
||||
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] })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
currentDir = path.dirname(currentDir)
|
||||
}
|
||||
})
|
||||
;(manifest[notAFile] as any) = false
|
||||
;(directories[notAFile] as any) = false
|
||||
setupManifest = noop
|
||||
}
|
||||
|
||||
@@ -163,32 +165,26 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
realpathSync: function realpathSync(filepath: any, options: any) {
|
||||
setupManifest()
|
||||
const key = getKey(filepath)
|
||||
if (isString(filepath) && (manifest[filepath] || manifest[key])) {
|
||||
if (manifest[key]) {
|
||||
return filepath
|
||||
}
|
||||
return originalFsMethods.realpathSync.call(fs, filepath, options)
|
||||
},
|
||||
readdir: function readdir(filepath: string | Buffer, options: any, callback: any) {
|
||||
setupManifest()
|
||||
filepath = filepath.toString()
|
||||
if ('function' === typeof options) {
|
||||
callback = options
|
||||
options = { encoding: 'utf8' }
|
||||
}
|
||||
const dir = directories[getKey(filepath)]
|
||||
if (dir) {
|
||||
process.nextTick(() => {
|
||||
//todo merge with original?
|
||||
callback(null, Object.keys(dir))
|
||||
})
|
||||
if ('function' === typeof options) {
|
||||
callback = options
|
||||
options = { encoding: 'utf8' }
|
||||
}
|
||||
process.nextTick(() => callback(null, Object.keys(dir)))
|
||||
} else {
|
||||
return originalFsMethods.readdir.apply(fs, arguments)
|
||||
}
|
||||
},
|
||||
|
||||
readdirSync: function readdirSync(filepath: string | Buffer, options: any) {
|
||||
setupManifest()
|
||||
filepath = filepath.toString()
|
||||
const dir = directories[getKey(filepath)]
|
||||
if (dir) {
|
||||
return Object.keys(dir)
|
||||
@@ -198,8 +194,8 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
|
||||
readFile: function readFile(filepath: any, options: any, callback: any) {
|
||||
setupManifest()
|
||||
const entry = manifest[filepath] || manifest[getKey(filepath)]
|
||||
if (!entry || !isString(filepath)) {
|
||||
const entry = manifest[getKey(filepath)]
|
||||
if (!entry) {
|
||||
return originalFsMethods.readFile.apply(fs, arguments)
|
||||
}
|
||||
const [offset, length] = entry
|
||||
@@ -230,8 +226,8 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
},
|
||||
createReadStream: function createReadStream(filepath: any, options: any) {
|
||||
setupManifest()
|
||||
const entry = manifest[filepath] || manifest[getKey(filepath)]
|
||||
if (!entry || !isString(filepath)) {
|
||||
const entry = manifest[getKey(filepath)]
|
||||
if (!entry) {
|
||||
return originalFsMethods.createReadStream.apply(fs, arguments)
|
||||
}
|
||||
const [offset, length] = entry
|
||||
@@ -248,9 +244,8 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
},
|
||||
readFileSync: function readFileSync(filepath: any, options: any) {
|
||||
setupManifest()
|
||||
|
||||
const entry = manifest[filepath] || manifest[getKey(filepath)]
|
||||
if (!entry || !isString(filepath)) {
|
||||
const entry = manifest[getKey(filepath)]
|
||||
if (!entry) {
|
||||
return originalFsMethods.readFileSync.apply(fs, arguments)
|
||||
}
|
||||
const [offset, length] = entry
|
||||
@@ -263,14 +258,14 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
return encoding ? result.toString(encoding) : result
|
||||
},
|
||||
statSync: function statSync(filepath: string | Buffer) {
|
||||
const stat = isString(filepath) && ownStat(filepath)
|
||||
const stat = ownStat(filepath)
|
||||
if (stat) {
|
||||
return stat
|
||||
}
|
||||
return originalFsMethods.statSync.apply(fs, arguments)
|
||||
},
|
||||
stat: function stat(filepath: string | Buffer, callback: any) {
|
||||
const stat = isString(filepath) && ownStat(filepath)
|
||||
const stat = ownStat(filepath)
|
||||
if (stat) {
|
||||
process.nextTick(() => {
|
||||
callback(null, stat)
|
||||
|
||||
+2
-2
@@ -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
@@ -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) {
|
||||
if (compiler.options.loglevel !== 'silent' && error) {
|
||||
process.stderr.write(EOL + error.message + EOL)
|
||||
}
|
||||
compiler.quit()
|
||||
compiler && compiler.quit(error)
|
||||
if (callback) return callback(error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
+39
-33
@@ -1,6 +1,6 @@
|
||||
import * as parseArgv from 'minimist'
|
||||
import { NexeCompiler } from './compiler'
|
||||
import { isWindows } from './util'
|
||||
import { NexeCompiler, NexeError } from './compiler'
|
||||
import { isWindows, STDIN_FLAG } from './util'
|
||||
import { basename, extname, join, isAbsolute, resolve } from 'path'
|
||||
import { getTarget, NexeTarget } from './target'
|
||||
import { EOL, homedir } from 'os'
|
||||
@@ -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) {
|
||||
@@ -194,11 +191,16 @@ function isEntryFile(filename?: string): filename is string {
|
||||
return Boolean(filename && !isAbsolute(filename))
|
||||
}
|
||||
|
||||
export function resolveEntry(input: string, cwd: string, maybeEntry?: string) {
|
||||
if (input === '-' || maybeEntry === '-') {
|
||||
return ''
|
||||
}
|
||||
export function resolveEntry(
|
||||
input: string,
|
||||
cwd: string,
|
||||
maybeEntry: string | undefined,
|
||||
bundle: boolean | string
|
||||
) {
|
||||
let result = null
|
||||
if (input === '-' || maybeEntry === '-') {
|
||||
return STDIN_FLAG
|
||||
}
|
||||
if (input && isAbsolute(input)) {
|
||||
return input
|
||||
}
|
||||
@@ -206,19 +208,19 @@ export function resolveEntry(input: string, cwd: string, maybeEntry?: string) {
|
||||
const inputPath = padRelative(input)
|
||||
result = resolveFileNameSync(cwd, inputPath)
|
||||
}
|
||||
|
||||
if (isEntryFile(maybeEntry) && (!result || !result.absPath)) {
|
||||
const inputPath = padRelative(maybeEntry)
|
||||
result = resolveFileNameSync(cwd, inputPath)
|
||||
}
|
||||
if (!process.stdin.isTTY) {
|
||||
return ''
|
||||
if (!process.stdin.isTTY && (!result || !result.absPath) && bundle === defaults.bundle) {
|
||||
return STDIN_FLAG
|
||||
}
|
||||
if (!result || !result.absPath) {
|
||||
result = resolveFileNameSync(cwd, '.')
|
||||
}
|
||||
if (!result.absPath) throw new Error(`Entry file "${input}" not found!`)
|
||||
|
||||
if (!result.absPath) {
|
||||
throw new NexeError(`Entry file "${input || ''}" not found!`)
|
||||
}
|
||||
return result.absPath
|
||||
}
|
||||
|
||||
@@ -234,8 +236,8 @@ function normalizeOptions(input?: Partial<NexeOptions>): NexeOptions {
|
||||
? resolve(cwd, options.temp)
|
||||
: process.env.NEXE_TEMP || join(homedir(), '.nexe')
|
||||
const maybeEntry = isCli(input) ? argv._[argv._.length - 1] : undefined
|
||||
options.input = resolveEntry(options.input, cwd, maybeEntry)
|
||||
options.enableStdIn = isCli(input) && options.input === ''
|
||||
options.input = resolveEntry(options.input, cwd, maybeEntry, options.bundle)
|
||||
options.enableStdIn = isCli(input) && options.input === STDIN_FLAG
|
||||
options.name = extractName(options)
|
||||
options.loglevel = extractLogLevel(options)
|
||||
options.flags = flatten(opts.flag, options.flags)
|
||||
@@ -263,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) {
|
||||
@@ -272,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])
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -6,8 +6,27 @@ export default async function disableNodeCli(compiler: NexeCompiler, next: () =>
|
||||
return next()
|
||||
}
|
||||
|
||||
if (semverGt(compiler.target.version, '9.99')) {
|
||||
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(
|
||||
'src/node.cc',
|
||||
'int i = 1; i < v8_argc; i++',
|
||||
'int i = v8_argc; i < v8_argc; i++'
|
||||
)
|
||||
let matches = 0
|
||||
await compiler.replaceInFileAsync('src/node.cc', /v8_argc > 1/g, match => {
|
||||
if (matches++) {
|
||||
return 'false'
|
||||
}
|
||||
return match
|
||||
})
|
||||
} else {
|
||||
const nodeccMarker = 'argv[index][0] =='
|
||||
|
||||
|
||||
+54
-6
@@ -1,20 +1,68 @@
|
||||
import { NexeCompiler } from '../compiler'
|
||||
import { resolve } from 'path'
|
||||
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'
|
||||
|
||||
function getStdIn(stdin: Readable): Promise<string> {
|
||||
return new Promise(resolve => {
|
||||
let out = ''
|
||||
stdin
|
||||
.setEncoding('utf8')
|
||||
.on('readable', () => {
|
||||
let current
|
||||
while ((current = stdin.read())) {
|
||||
out += current
|
||||
}
|
||||
})
|
||||
.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();'
|
||||
|
||||
if (!bundle) {
|
||||
await compiler.addResource(resolve(cwd, input))
|
||||
return next()
|
||||
}
|
||||
|
||||
if (!input) {
|
||||
let code = ''
|
||||
if (typeof bundle === 'string') {
|
||||
code = await require(bundle).createBundle(compiler.options)
|
||||
}
|
||||
|
||||
if (input === STDIN_FLAG && (code = code || dequote(await getStdIn(process.stdin)))) {
|
||||
compiler.stdinUsed = true
|
||||
compiler.entrypoint = './__nexe_stdin.js'
|
||||
await compiler.addResource(resolve(cwd, compiler.entrypoint), code)
|
||||
return next()
|
||||
}
|
||||
|
||||
const { files } = 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 NexeError('Parsing Error:\n' + warnings.join('\n'))
|
||||
}
|
||||
|
||||
await each(Object.keys(files), (filename: string) => compiler.addResource(filename), {
|
||||
concurrency: 10
|
||||
})
|
||||
|
||||
+20
-42
@@ -1,24 +1,9 @@
|
||||
import { normalize, relative, resolve } from 'path'
|
||||
import { dirname, normalize, relative } from 'path'
|
||||
import { createWriteStream, chmodSync, statSync } from 'fs'
|
||||
import { dequote } from '../util'
|
||||
import { Readable } from 'stream'
|
||||
import { NexeCompiler } from '../compiler'
|
||||
import { NexeTarget } from '../target'
|
||||
|
||||
function getStdIn(stdin: Readable): Promise<string> {
|
||||
return new Promise(resolve => {
|
||||
let out = ''
|
||||
stdin
|
||||
.setEncoding('utf8')
|
||||
.on('readable', () => {
|
||||
let current
|
||||
while ((current = stdin.read())) {
|
||||
out += current
|
||||
}
|
||||
})
|
||||
.on('end', () => resolve(out))
|
||||
})
|
||||
}
|
||||
import { STDIN_FLAG } from '../util'
|
||||
import mkdirp = require('mkdirp')
|
||||
|
||||
/**
|
||||
* The "cli" step detects the appropriate input. If no input options are passed,
|
||||
@@ -26,49 +11,42 @@ function getStdIn(stdin: Readable): Promise<string> {
|
||||
* After all the build steps have run, the output (the executable) is written to a file or piped to stdout.
|
||||
*
|
||||
* Configuration:
|
||||
* - compiler.options.input - file path to the input bundle.
|
||||
* - fallbacks: stdin, package.json#main
|
||||
* - compiler.options.output - file path to the output executable.
|
||||
* - fallbacks: stdout, nexe_ + epoch + ext
|
||||
*
|
||||
* @param {*} compiler
|
||||
* @param {*} next
|
||||
*/
|
||||
export default async function cli(compiler: NexeCompiler, next: () => Promise<void>) {
|
||||
const { log } = compiler
|
||||
let stdInUsed = false
|
||||
if (!process.stdin.isTTY && compiler.options.enableStdIn) {
|
||||
stdInUsed = true
|
||||
compiler.entrypoint = './__nexe_stdin.js'
|
||||
const code = dequote(await getStdIn(process.stdin))
|
||||
await compiler.addResource(resolve(compiler.options.cwd, compiler.entrypoint), code)
|
||||
} else {
|
||||
compiler.entrypoint = './' + relative(compiler.options.cwd, compiler.options.input)
|
||||
}
|
||||
compiler.startup = ';require("module").runMain();'
|
||||
await next()
|
||||
const { log } = compiler,
|
||||
target = compiler.options.targets.shift() as NexeTarget,
|
||||
deliverable = await compiler.compileAsync(target),
|
||||
output = normalize(compiler.output!)
|
||||
|
||||
const target = compiler.options.targets.shift() as NexeTarget
|
||||
const deliverable = await compiler.compileAsync(target)
|
||||
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: '${
|
||||
stdInUsed ? (compiler.options.mangle ? '[stdin]' : '[none]') : inputFile
|
||||
}' written to: ${outputFile}`
|
||||
compiler.stdinUsed
|
||||
? compiler.options.mangle
|
||||
? STDIN_FLAG
|
||||
: '[none]'
|
||||
: inputFileLogOutput
|
||||
}' written to: ${outputFileLogOutput}`
|
||||
)
|
||||
resolve(compiler.quit())
|
||||
}
|
||||
|
||||
+42
-12
@@ -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,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>) {
|
||||
|
||||
+5
-1
@@ -22,7 +22,11 @@ export default function(compiler: NexeCompiler, next: () => Promise<void>) {
|
||||
compiler.shims.push(
|
||||
wrap(`
|
||||
if (!process.send) {
|
||||
process.argv.splice(1,0, require.resolve(${JSON.stringify(compiler.entrypoint)}))
|
||||
const path = require('path')
|
||||
const entry = path.resolve(path.dirname(process.execPath),${JSON.stringify(
|
||||
compiler.entrypoint
|
||||
)})
|
||||
process.argv.splice(1,0, entry)
|
||||
}
|
||||
`)
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import pify = require('pify')
|
||||
import rimraf = require('rimraf')
|
||||
|
||||
const rimrafAsync = pify(rimraf)
|
||||
export const STDIN_FLAG = '[stdin]'
|
||||
|
||||
export async function each<T>(
|
||||
list: T[] | Promise<T[]>,
|
||||
|
||||
@@ -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
@@ -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
@@ -3,7 +3,7 @@
|
||||
"target":"es5",
|
||||
"skipLibCheck": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es2017"],
|
||||
"lib": ["es2018"],
|
||||
"module": "commonjs",
|
||||
"outDir": "./lib",
|
||||
"strict": true
|
||||
|
||||
Reference in New Issue
Block a user