Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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,3 +1,4 @@
|
||||
dist: xenial
|
||||
language: node_js
|
||||
node_js:
|
||||
- '6'
|
||||
|
||||
@@ -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.
|
||||
@@ -145,12 +143,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",
|
||||
|
||||
@@ -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
+844
-239
File diff suppressed because it is too large
Load Diff
+19
-18
@@ -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.0",
|
||||
"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.1.0",
|
||||
"got": "^9.6.0",
|
||||
"minimist": "^1.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"multistream": "^2.1.1",
|
||||
"ora": "^3.0.0",
|
||||
"ora": "^3.2.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",
|
||||
"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.14.0",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"tslint-plugin-prettier": "^2.0.1",
|
||||
"typescript": "^3.1.6"
|
||||
"typescript": "^3.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
+28
-53
@@ -1,7 +1,6 @@
|
||||
import { delimiter, dirname, 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 {
|
||||
@@ -26,6 +25,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 +35,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 +89,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,7 +100,7 @@ export class NexeCompiler {
|
||||
/**
|
||||
* The file path of node binary
|
||||
*/
|
||||
private nodeSrcBinPath: string
|
||||
public nodeSrcBinPath: string
|
||||
|
||||
constructor(public options: NexeOptions) {
|
||||
const { python } = (this.options = options)
|
||||
@@ -155,9 +166,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,15 +177,15 @@ 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`')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +218,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 +232,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,39 +247,6 @@ 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
|
||||
@@ -296,12 +274,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!)
|
||||
|
||||
+43
-45
@@ -34,6 +34,8 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
const { blobPath, resources: manifest } = binary
|
||||
const { resourceStart, stat } = binary.layout
|
||||
const 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,
|
||||
@@ -42,23 +44,25 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
|
||||
isDirectory = isFile,
|
||||
path = require('path')
|
||||
|
||||
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(filepath)
|
||||
|
||||
if (isWin && key.substr(1, 2) === ':\\') {
|
||||
key = key[0].toUpperCase() + key.substr(1)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
const statTime = function() {
|
||||
return {
|
||||
@@ -81,22 +85,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 +142,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 +168,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 +197,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 +229,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 +247,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 +261,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)
|
||||
}
|
||||
|
||||
+19
-14
@@ -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'
|
||||
@@ -165,7 +165,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 +194,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 +211,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 +239,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)
|
||||
|
||||
@@ -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] =='
|
||||
|
||||
|
||||
+44
-4
@@ -1,20 +1,60 @@
|
||||
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 { 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))
|
||||
})
|
||||
}
|
||||
|
||||
export default async function bundle(compiler: NexeCompiler, next: any) {
|
||||
const { bundle, cwd, input } = compiler.options
|
||||
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) {
|
||||
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 } = await resolveFiles(input, { cwd, expand: true, loadContent: false })
|
||||
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
|
||||
})
|
||||
|
||||
+4
-35
@@ -1,24 +1,8 @@
|
||||
import { normalize, relative, resolve } from 'path'
|
||||
import { 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'
|
||||
|
||||
/**
|
||||
* The "cli" step detects the appropriate input. If no input options are passed,
|
||||
@@ -26,28 +10,13 @@ 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
|
||||
const target = compiler.options.targets.shift() as NexeTarget
|
||||
const deliverable = await compiler.compileAsync(target)
|
||||
|
||||
@@ -67,7 +36,7 @@ export default async function cli(compiler: NexeCompiler, next: () => Promise<vo
|
||||
const outputFile = relative(process.cwd(), output)
|
||||
step.log(
|
||||
`Entry: '${
|
||||
stdInUsed ? (compiler.options.mangle ? '[stdin]' : '[none]') : inputFile
|
||||
compiler.stdinUsed ? (compiler.options.mangle ? STDIN_FLAG : '[none]') : inputFile
|
||||
}' written to: ${outputFile}`
|
||||
)
|
||||
resolve(compiler.quit())
|
||||
|
||||
+52
-12
@@ -2,7 +2,9 @@ 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 { getLatestGitRelease } from '../releases'
|
||||
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 +23,65 @@ function fetchNodeSourceAsync(dest: string, url: string, step: LogStep, options
|
||||
.then(() => step.log(`Node source extracted to: ${dest}`))
|
||||
}
|
||||
|
||||
async function fetchPrebuiltBinary(compiler: NexeCompiler, step: any) {
|
||||
let downloadOptions = compiler.options.downloadOptions
|
||||
const target = compiler.target
|
||||
|
||||
if (compiler.options.ghToken) {
|
||||
downloadOptions = Object.assign({}, downloadOptions)
|
||||
downloadOptions.headers = Object.assign({}, downloadOptions.headers, {
|
||||
Authorization: 'token ' + compiler.options.ghToken
|
||||
})
|
||||
}
|
||||
|
||||
const githubRelease = await getLatestGitRelease(downloadOptions)
|
||||
const assetName = target.toString()
|
||||
const asset = githubRelease.assets.find(x => x.name === assetName)
|
||||
|
||||
if (!asset) {
|
||||
throw new NexeError(`${assetName} not available, create it using the --build flag`)
|
||||
}
|
||||
const filename = compiler.getNodeExecutableLocation(target)
|
||||
|
||||
await download(
|
||||
asset.browser_download_url,
|
||||
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()}%`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`
|
||||
const step = log.step(
|
||||
`Downloading ${build ? '' : 'pre-built '}Node.js${build ? `source from: ${url}` : ''}`
|
||||
)
|
||||
const exeLocation = compiler.getNodeExecutableLocation(build ? undefined : target)
|
||||
const 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>) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
+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