Compare commits

...

15 Commits

Author SHA1 Message Date
Jared Allard bbe26640df npm: prepare version 1.0.7, release 1.0.6 2016-01-28 15:38:43 -08:00
Jared Allard 54675f0e23 bundle: search top-level directories for browserify as well. Fixes #170. Implement support for js-flags in 0.12.x 2016-01-28 15:32:33 -08:00
Jared Allard 3ac02efd18 readme: document opts for nexe.compile and package.json 2016-01-28 14:50:37 -08:00
Jared Allard b100922d91 test: dont append os ext to test file. 2016-01-28 14:29:21 -08:00
Jared Allard 87660c3682 exe: fixes #168. Implements package.json nexe.runtime.js-flags for v8 flags. 2016-01-28 14:25:31 -08:00
Jared Allard 635cd62196 exe: handle tar extraction & download failures better 2016-01-24 21:08:38 -08:00
Jared Allard 336a5ea2e3 misc: remove .cupboard 2016-01-24 21:01:58 -08:00
Jared Allard 7fe0d207de exe: better configure error, logs, fix a bug in handling spawn args for certain node versions 2016-01-24 20:59:58 -08:00
Jared Allard 3e708ca916 npm: prepare 1.0.5 2016-01-24 17:30:40 -08:00
Jared Allard de84339c80 exe: dont check for options, yet. fixes #163 2016-01-24 17:28:04 -08:00
Jared Allard fb81a9c75e npm: prepare 1.0.4 2016-01-22 15:00:23 -08:00
Jared Allard 0e34905ddc npm/bundle: remove through depend that wasnt even used 2016-01-22 14:58:31 -08:00
Jared Allard c1e7416644 npm: fix version issue, and don't bundle src in builds 2016-01-22 14:51:16 -08:00
Jared Allard 53daa903ea readme: remove 5.x.x notice 2016-01-22 14:42:40 -08:00
Jared Allard 9e2a5f1c78 exe/bundle: fix bugs intoduced in 1.0.0. v1.0.1. Fixes #162 2016-01-22 14:37:27 -08:00
17 changed files with 303 additions and 84 deletions
-4
View File
@@ -1,4 +0,0 @@
[commands]
proj = subl .
.DS_Store
+4 -1
View File
@@ -5,5 +5,8 @@ src
nexe.exe
nexe
npm-debug.log
# test/**/src
test/**/src
test/**/out.nex
test/**/test.nex
test/**/tmp
test/**/node_modules
View File
+18 -11
View File
@@ -3,8 +3,6 @@
[![Join the chat at https://gitter.im/crcn/nexe](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jaredallard/nexe?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Dependency Status](https://david-dm.org/jaredallard/nexe.svg)](https://david-dm.org/crcn/nexe)
[![Stories in Ready](https://badge.waffle.io/jaredallard/nexe.svg?label=ready&title=Ready)](http://waffle.io/jaredallard/nexe)
# NOTICE: Node 5.x.x is broken right now.
Nexe is a command-line utility that compiles your Node.js application into a single executable file.
![screen shot 2014-02-28 at 10 32 54 am](https://f.cloud.github.com/assets/757408/2296993/c276f7b6-a0a6-11e3-86d3-e6c5feba2a85.png)
@@ -136,16 +134,23 @@ Options:
var nexe = require('nexe');
nexe.compile({
input: 'input.js',
output: 'path/to/bin',
nodeVersion: '5.5.0',
nodeTempDir: 'src',
python: 'path/to/python',
resourceFiles: [ 'path/to/a/file' ],
flags: true,
input: 'input.js', // where the input file is
output: 'path/to/bin', // where to output the compiled binary
nodeVersion: '5.5.0', // node version
nodeTempDir: 'src', // where to store node source.
nodeConfigureArgs: ['opt', 'val'], // for all your configure arg needs.
nodeMakeArgs: ["-j", "4"], // when you want to control the make process.
python: 'path/to/python', // for non-standard python setups. Or python 3.x forced ones.
resourceFiles: [ 'path/to/a/file' ], // array of files to embed.
flags: true, // use this for applications that need command line flags.
jsFlags: "--use_strict", // v8 flags
framework: "node" // node, nodejs, or iojs
}, function(err) {
console.log(err);
if(err) {
return console.log(err);
}
// do whatever
});
```
@@ -155,7 +160,7 @@ nexe.compile({
As of 0.4.0 you can now embed nexe options into package.json. Note that this Format
is still in works, so it is likely to change.
```
```json
"nexe": {
"input": "./bin/nexe",
"output": "nexe^$",
@@ -163,6 +168,7 @@ is still in works, so it is likely to change.
"runtime": {
"framework": "node",
"version": "5.5.0",
"js-flags": "--use_strict",
"ignoreFlags": true
}
}
@@ -171,6 +177,7 @@ is still in works, so it is likely to change.
Notes:
* output: can use ^$ for platform specific file extension
* js-flags: this is also known as v8 flags, and supports *all* v8 flags.
## Maintainers
+3 -3
View File
@@ -63,7 +63,7 @@ if(argv.h || argv.help) {
**/
function toAbsolute(pt) {
if(pt.substr(0, 1) == "/") return pt;
if(pt.substr(1, 3) == ":/") return pt; // for windows "c:/"
if(pt.substr(1, 3) == ":/") return pt; // for windows "c:/"
return path.join(process.cwd(), pt);
}
@@ -71,7 +71,7 @@ if(fs.lstatSync(argv.i).isDirectory()) {
opts = nexe.package(path.join(argv.i, "package.json"), argv);
nexe.compile(opts, function(error) {
if(error) {
console.log(error.message);
return console.log(error.message);
}
});
} else {
@@ -89,7 +89,7 @@ if(fs.lstatSync(argv.i).isDirectory()) {
},
function(error) {
if(error) {
console.log(error.message);
return console.log(error.message);
}
}
);
+27 -6
View File
@@ -22,16 +22,15 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**/
var mdeps = require("module-deps"),
var mdeps = require("module-deps"),
path = require("path"),
spawn = require('child_process').spawn,
fs = require("fs"),
through = require("through2"),
async = require("async"),
browserify = require('browserify'),
builtins = require("builtins"),
_log = require("./log");
_log = require("./log");
/**
* User browserify to create a "packed" file.
@@ -43,9 +42,25 @@ var mdeps = require("module-deps"),
function bundle (input, nc, complete) {
var bundlePath = path.join(nc, "lib", "nexe.js");
var ws = fs.createWriteStream(bundlePath);
var proc = spawn('node', [path.join(__dirname, '../', 'node_modules/browserify/bin/cmd.js'), '--node', input ]);
var browserifyExec;
// TODO: Get path of nexe directory, and refer to it.
var browserifyLocations = [ // TODO: Do this programattically.
'This is to ignore the 0 location.',
path.join(__dirname, '../', 'node_modules/browserify/bin/cmd.js'),
path.join(__dirname, '../../', 'node_modules/browserify/bin/cmd.js'),
path.join(__dirname, '../../../', 'node_modules/browserify/bin/cmd.js'),
path.join(__dirname, '../../../../', 'node_modules/browserify/bin/cmd.js')
]
for(var i = 0; i !== (browserifyLocations.length-1); i++) {
if(fs.existsSync(browserifyLocations[i])) {
browserifyExec = browserifyLocations[i];
_log('found browserify in', browserifyExec);
break;
}
}
var proc = spawn('node', [browserifyExec, '--node', input ]);
proc.stdout.pipe(ws);
@@ -57,6 +72,9 @@ function bundle (input, nc, complete) {
proc.stderr.on('data', function(data) {
console.error(data.toString('ascii'));
if(!fs.existsSync(input)) {
_log('error', 'Your input file doesn\'t exist!');
}
_log('error', 'Browserify failed to launch');
process.exit(1);
});
@@ -85,3 +103,6 @@ function bundle (input, nc, complete) {
complete();
});
});
}
module.exports = bundle;
+180 -14
View File
@@ -28,6 +28,7 @@ var async = require("async"),
request = require("request"),
path = require("path"),
fs = require("fs"),
colors = require('colors'),
ncp = require("ncp").ncp,
ProgressBar = require("progress"),
child_process = require("child_process"),
@@ -52,6 +53,8 @@ var option_list = [
"nodeTempDir",
"flags",
"framework",
"nodeConfigureArgs",
"nodeMakeArgs",
"nodeVersion"
]
@@ -74,12 +77,12 @@ exports.compile = function (options, complete) {
process.exit()
}
option_list.forEach(function(v) {
/* option_list.forEach(function(v) {
if(options[v] === undefined) {
_log("error", "option "+v+" was empty")
process.exit();
}
});
}); */
/**
* Have we been given a custom flag for python executable?
@@ -129,7 +132,7 @@ exports.compile = function (options, complete) {
// continue down along the async road
next();
})
});
} else {
next();
}
@@ -139,7 +142,7 @@ exports.compile = function (options, complete) {
* first download node
*/
function downloadNode (next) {
_downloadNode(version, options.nodeTempDir, nodeConfigureArgs, nodeMakeArgs, next);
_downloadNode(version, options.nodeTempDir, options.nodeConfigureArgs, options.nodeMakeArgs, next);
},
/**
@@ -183,6 +186,14 @@ exports.compile = function (options, complete) {
}
},
function monkeyPatchv8FlagsCc (next) {
if(options.jsFlags) {
return _monkeyPatchv8FlagsCc(nodeCompiler, options, next);
}
return next();
},
/**
* monkeypatch child_process.js so nexejs knows when it is a forked process
*/
@@ -242,7 +253,7 @@ exports.compile = function (options, complete) {
"This indicates a failure in the build process. " +
"There is likely additional information above."
);
throw new Error("The release executable was not built ('" + nodeCompiler.releasePath + "')");
process.exit(1);
} else {
next();
}
@@ -356,6 +367,11 @@ function _downloadNode(version, directory, nodeConfigureArgs, nodeMakeArgs, comp
tar.stderr.pipe(process.stderr);
tar.on("close", function () { next(); })
tar.on("error", function (err) {
console.log(err);
_log("error", "failed to extract the node tar file.");
process.exit(1);
});
}
},
@@ -421,12 +437,19 @@ function _getNodeCompiler (nodeFileDir, nodeConfigureArgs, nodeMakeArgs, complet
version: path.basename(nodeFileDir),
releasePath: path.join(dir, "out", "Release", binary),
make: function (next) {
var cfg = "./configure", configure;
if(isPy !== "python") {
configure = spawn(isPy, [cfg].concat(nodeConfigureArgs), { cwd: dir });
} else {
configure = spawn(cfg, nodeConfigureArgs, { cwd: dir });
}
var cfg = "./configure",
configure;
var conf = [cfg];
if(isPy !== "python") {
conf = [conf].concat(nodeConfigureArgs);
}
// should work for all use cases now.
configure = spawn(isPy, conf, {
cwd: dir.toString('ascii')
});
// local function, move to top eventually
function _loop(dir) {
@@ -461,6 +484,29 @@ function _getNodeCompiler (nodeFileDir, nodeConfigureArgs, nodeMakeArgs, complet
configure.stdout.pipe(process.stdout);
configure.stderr.pipe(process.stderr);
// on error
configure.on("error", function(err) {
console.log('Error:', err);
console.log('');
console.log('Details:');
console.log('command =', isPy, cfg, conf_args || '');
console.log('cwd =', dir);
var configure_path = path.join(dir, 'configure');
var contains_configure = fs.existsSync(configure_path);
console.log('cwd contains configure,', (contains_configure ? colors.green('yes') : colors.red('no')));
var configure_size = fs.statSync(configure_path).size;
console.log('configure is non-zero size,', ((configure_size > 0 ) ? colors.green('yes') : colors.red('no')));
_log("error", "failed to launch configure.");
process.exit(1);
});
// when it's finished
configure.on("close", function () {
if(isPy !== "python") {
/**
@@ -473,13 +519,24 @@ function _getNodeCompiler (nodeFileDir, nodeConfigureArgs, nodeMakeArgs, complet
// loop over depends
_loop(dir);
}
if(nodeMakeArgs === undefined) {
nodeMakeArgs = [];
}
var platformMake = "make";
if (os.platform().match(/bsd$/) != null) {
platformMake = "gmake";
}
var make = spawn(platformMake, nodeMakeArgs, { cwd: dir });
make.stdout.pipe(process.stdout);
make.stderr.pipe(process.stderr);
make.on("error", function(err) {
console.log(err);
_log("error", "failed to run make.");
process.exit(1);
})
make.on("close", function () {
next();
});
@@ -621,6 +678,107 @@ function _monkeyPatchMainCc(compiler, complete) {
}
/**
* Patch flags.cc from deps/v8/src to use hard-coded flags.
* this function is very closely ready to accept custom injection code.
**/
function _monkeyPatchv8FlagsCc(compiler, options, complete) {
var mainPath = path.join(compiler.dir, "deps/v8/src", "flags.cc");
fs.readFile(mainPath, {encoding: 'utf8'}, function(err, contents) {
if(err) {
return _log('error', 'failed to read', mainPath);
}
// Super simple injection here. Perhaps make it an array at somepoint?
var injection = '\
const char* nexevargs = "{{args}}";\n\
int nexevargslen = strlen(nexevargs);\n\
SetFlagsFromString(nexevargs, nexevargslen);\n\
';
var injectionSplit = injection.split('\n');
var injectionLength = injectionSplit.length;
var contentsSplit = contents.split('\n');
var contentsLength = contentsSplit.length;
var lastInjectionLine = injectionSplit[injectionLength-2];
var lineToInjectAfter = contentsSplit.indexOf(' ComputeFlagListHash();');
var haveWeInjectedBefore = contentsSplit.indexOf(lastInjectionLine);
var lineInjectDifference = contentsLength - lineToInjectAfter;
// support for 0.12.x
if(lineToInjectAfter===-1) {
_log('warn', 'Using an expiramental support patch for 0.12.x');
lineToInjectAfter = contentsSplit.indexOf('#undef FLAG_MODE_DEFINE_IMPLICATIONS');
}
// this is debug, comment out.
// _log('v8 injection is', injectionLength, 'newlines long');
// _log('v8 flags source is', contentsLength, 'newlines long');
// console.log(finalContents)
var finalContents,
dontCombine;
if(lineToInjectAfter !== -1 && haveWeInjectedBefore === -1) {
_log('injecting v8 args c++');
// super debug
// _log('v8 injection determined by', lastInjectionLine);
// _log('v8 inject after line', lineToInjectAfter);
// _log('v8 inject needs to shift', lineInjectDifference, 'amount of lines by', injectionLength);
// compute out the amount of space we'll need in this.
var startShiftLine = contentsLength-1; // minus one to make up for 0 arg line.
var endShiftLine = lineToInjectAfter;
var injectRoom = injectionLength-1;
injectionSplit[0] = injectionSplit[0].replace('{{args}}', options.jsFlags);
for (var i = startShiftLine; i !== endShiftLine; i--) {
contentsSplit[i+injectRoom] = contentsSplit[i];
contentsSplit[i] = '';
}
var injectionPos = 0;
for(var i = 0; i !== injectionLength-1; i++) {
contentsSplit[(lineToInjectAfter+1)+injectionPos] = injectionSplit[injectionPos];
injectionPos++;
}
} else if(lineToInjectAfter !== -1 && haveWeInjectedBefore !== -1) {
_log('re-injecting v8 args');
dontCombine = true;
finalContents = contentsSplit.join('\n');
finalContents = finalContents.replace(/const char\* nexevargs = "[A-Z\-\_]*";/gi,
'const char* nexevargs = "'+options.jsFlags+'";');
} else {
_log('warn', 'failed to find a suitable injection point for v8 args.',
'File a bug report with the node version and log.');
_log('lineToInjectAfter='+lineToInjectAfter, 'haveWeInjectedBefore='+haveWeInjectedBefore);
return process.exit(1);
}
if(!dontCombine) {
finalContents = contentsSplit.join('\n');
}
fs.writeFile(mainPath, finalContents, {encoding: 'utf8'}, function(err) {
if(err) {
_log('error', 'failed to write to', mainPath);
return process.exit(1);
}
return complete();
})
});
}
/**
* Get the first directory of a string.
*/
function _getFirstDirectory (dir) {
@@ -635,6 +793,7 @@ function _getFirstDirectory (dir) {
}
/**
* Log the progress of a request object.
*/
function _logProgress (req) {
@@ -646,7 +805,7 @@ function _logProgress (req) {
complete: "=",
incomplete: " ",
total: len,
width: ((isWin) ? 100 : process.stdout.columns - 2) // windows doesn't output colums correctly
width: 100 // just use 100
});
req.on("data", function (chunk) {
@@ -654,6 +813,12 @@ function _logProgress (req) {
});
});
req.on("error", function(err) {
console.log(err);
_log("error", "failed to download node sources,");
process.exit(1);
});
return req;
}
@@ -664,6 +829,7 @@ function _logProgress (req) {
* @param {object} options - fallback options
*
* @todo implement options overriding package defaults.
* @todo make this much less hackily implemented....
*
* @return {object} nexe.compile options object
**/
@@ -688,13 +854,13 @@ exports.package = function(path, options) {
var obj = {
input: (_package.nexe.input || options.i),
output: (_package.nexe.output || options.o),
flags: (_package.nexe.runtime.ignoreFlags || options.f),
nodeConfigureArgs: (_package.nexe.runtime.nodeConfigureArgs || []),
flags: (_package.nexe.runtime.ignoreFlags || (options.f || false)),
nodeMakeArgs: (_package.nexe.runtime.nodeMakeArgs || []),
resourceFiles: (_package.nexe.resourceFiles),
nodeVersion: (_package.nexe.runtime.version || options.r),
nodeConfigureArgs: (_package.nexe.runtime.nodeConfigureArgs || []),
nodeMakeArgs: (_package.nexe.runtime.nodeMakeArgs || []),
jsFlags: (_package.nexe.runtime['js-flags'] || false),
python: (_package.nexe.python || options.p),
nodeTempDir: (_package.nexe.temp || options.t),
framework: (_package.nexe.runtime.framework || options.f)
+3 -2
View File
@@ -1,5 +1,6 @@
/**
* Copyright (c) 2013 Craig Condon
* Copyright (c) 2015-2016 Jared Allard
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -22,6 +23,8 @@
*
**/
var colors = require('colors');
/**
* standard output, takes 3 different types.
* log, error, and warn
@@ -31,8 +34,6 @@
**/
function _log () {
var colors = require('colors');
var args = Array.prototype.slice.call(arguments, 0),
level = args.shift();
+1 -2
View File
@@ -3,7 +3,7 @@
"name": "nexe",
"description": "create single executables out of your [node/io].js applications",
"license": "MIT",
"version": "1.0.0",
"version": "1.0.7",
"contributors": [
{
"name": "Criag Condon",
@@ -32,7 +32,6 @@
"sprintf": "~0.1.5",
"step": "0.0.x",
"tar.gz": "1.0.2",
"through": "^2.3.8",
"yargs": "^3.32.0"
},
"nexe": {
Binary file not shown.
-17
View File
@@ -1,17 +0,0 @@
/**
* Test Express with nexe
**/
console.log('express init');
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.send('It works!');
});
app.listen(8000, function() {
console.log('Listening on port 8000');
});
-24
View File
@@ -1,24 +0,0 @@
{
"name": "express-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"nexe": {
"input": "./index.js",
"output": "express-test^$",
"temp": "src",
"runtime": {
"framework": "nodejs",
"version": "5.5.0",
"ignoreFlags": true
}
},
"dependencies": {
"express": "^4.13.4"
}
}
+13
View File
@@ -0,0 +1,13 @@
/**
* Test to verify if we support strict mode (flags)
*
* @author Jared Allard <jaredallard@outlook.com>
* @version 0.0.1
* @license MIT
**/
// "use strict"; w/o --use_strict
var isStrict = (function() { return !this; })();
console.log('test:strict-mode:status =', isStrict);
+15
View File
@@ -0,0 +1,15 @@
{
"name": "flags-test",
"nexe": {
"input": "./index.js",
"output": "test.nex",
"temp": "src",
"runtime": {
"framework": "node",
"version": "0.10.0",
"ignoreFlags": false,
"js-flags": "--use_strict",
"node-args": ""
}
}
}
+23
View File
@@ -0,0 +1,23 @@
"use strict";
var gulp = require('gulp');
var nexe = require('nexe');
gulp.task( "compile", ( callback ) => {
let options = {
input: "index.js",
output: "test.nex",
python: "python",
nodeTempDir: "./tmp",
nodeVersion: "latest",
flags: false,
framework: "nodejs"
};
nexe.compile( options, ( err ) => {
console.log( err );
callback( err );
} );
} );
gulp.task('default', ['compile']);
+1
View File
@@ -0,0 +1 @@
console.log('Hello, world!');
+15
View File
@@ -0,0 +1,15 @@
{
"name": "gulp-test-170",
"version": "0.0.1",
"description": "gulpfile.js issue #170",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jared Allard <jaredallard@outlook.com>",
"license": "MIT",
"dependencies": {
"gulp": "^3.9.0",
"nexe": "^1.0.5"
}
}