Modify readme, implement cross-plat --python <loc> closes #94

This commit is contained in:
RainbowDashDC
2015-02-14 01:50:32 -08:00
parent 3ac298fe4f
commit 3b1d5a9fe1
5 changed files with 128 additions and 56 deletions
+43 -36
View File
@@ -1,5 +1,3 @@
## This repository is not actively maintained.
### Nexe ### Nexe
Nexe is a command-line utility that compiles your Node.js application into a single executable file. Nexe is a command-line utility that compiles your Node.js application into a single executable file.
@@ -9,7 +7,7 @@ Nexe is a command-line utility that compiles your Node.js application into a sin
### Motivation ### Motivation
- Ability to run multiple applications with *different* node.js runtimes. - Ability to run multiple applications with *different* node.js runtimes.
- Distributable binaries without needing node / npm. - Distributable binaries without needing node / npm.
- Starts faster. - Starts faster.
- Lockdown specific application versions, and easily rollback. - Lockdown specific application versions, and easily rollback.
@@ -20,69 +18,73 @@ Nexe is a command-line utility that compiles your Node.js application into a sin
- Linux / Mac / BSD / Windows - Linux / Mac / BSD / Windows
- Windows: Python 2.6 or 2.7 (in PATH), Visual Studio 2010 or 2012 - Windows: Python 2.6 or 2.7 (in PATH), Visual Studio 2010 or 2012
##Caveats ## Caveats
### Doesn't support native modules ### Doesn't support native modules
- Use the techniques below for working around dynamic require statments to exclude the module from the bundling, and deploy along side the executable in a node_module folder so your app can find it. Note: On windows you may need to have your app be named node.exe if .node file depends on node. - Use the techniques below for working around dynamic require statements to exclude the module from the bundling, and deploy along side the executable in a node_module folder so your app can find it. Note: On windows you may need to have your app be named node.exe if .node file depends on node.
###Doesn't support dynamic require statments ### Doesn't support dynamic require statements
Such As: Such As:
```
```javascript
var x = require(someVar); var x = require(someVar);
``` ```
In this case nexe won't bundle the file In this case nexe won't bundle the file
``` ```javascript
var x; var x;
if (someCheck) { if (someCheck) {
x = require("./ver1.js"); x = require("./ver1.js");
} } else {
else {
x = require("./var2.js"); x = require("./var2.js");
} }
``` ```
In this case nexe will bundle both files. In this case nexe will bundle both files.
Workarounds: Workarounds:
1) for dyanmic requires that you want bundled add the following into your project 1) for dynamic requires that you want bundled add the following into your project
```
```javascript
var dummyToForceIncludeForBundle = false; var dummyToForceIncludeForBundle = false;
if (dummyToForceIncludeForBundle) { if (dummyToForceIncludeForBundle) {
require("./loadedDynamicallyLater.js"); require("./loadedDynamicallyLater.js");
... // ...
} }
``` ```
this will trick the bundler into including them. this will trick the bundler into including them.
2) for dynamic files getting included that you don't want to be 2) for dynamic files getting included that you don't want to be
```
```javascript
var moduleName = "./ver2.js"; var moduleName = "./ver2.js";
if (someCheck) { if (someCheck) {
moduleName = "./ver1.js"; moduleName = "./ver1.js";
} }
var x = require(moduleName) var x = require(moduleName);
``` ```
Note: neither file will be bundled. Note: neither file will be bundled.
Using these two techniques you can change your application code so mdoules are not bundles, and generate a includes.js file as part of your build process so that the right files get bundled for your build configuration.
### __dirname Using these two techniques you can change your application code so modules are not bundles, and generate a includes.js file as part of your build process so that the right files get bundled for your build configuration.
Once the module is budnled it is part of the executable. __dirname is therefore the executable dir (process.execPath). Thus if you put resources on a realtive path from the the executable your app will be able to access them. ### &#95;&#95;dirname
If you had a data file at /dev/myNodeApp/stateManager/handler/data/some.csv Once the module is bundled it is part of the executable. &#95;&#95;dirname is therefore the executable dir (process.execPath). Thus if you put resources on a relative path from the the executable your app will be able to access them.
and a file at /dev/myNodeApp/stateManager/handler/loader.js
``` If you had a data file at `/dev/myNodeApp/stateManager/handler/data/some.csv`
and a file at `/dev/myNodeApp/stateManager/handler/loader.js`
```javascript
module.exports = fw.readFileSync(path.join(__dirname, "./data/some.csv")); module.exports = fw.readFileSync(path.join(__dirname, "./data/some.csv"));
``` ```
you would need to deploy some.csv in a sub dir data/ along side your executable You would need to deploy some.csv in a sub dir `data/` along side your executable
There are potential use cases for __dirname where the executable path is not the correct substitution, and could result in a silent error (possibly even in a dependciey that you are unaware of). There are potential use cases for &#95;&#95;dirname where the executable path is not the correct substitution, and could result in a silent error (possibly even in a dependency that you are unaware of).
Note: __filename will be 'undefined' Note: &#95;&#95;filename will be 'undefined'
### child_process.fork ### child_process.fork
@@ -99,13 +101,13 @@ Via NPM:
Or git: Or git:
```bash ```bash
git clone git clone
``` ```
### CLI Usage ### CLI Usage
````text ```text
Usage: nexe -i [sources] -o [binary] Usage: nexe -i [sources] -o [binary]
Options: Options:
@@ -115,12 +117,12 @@ Options:
-t, --temp The path to store node.js sources [default: /tmp/nexe] -t, --temp The path to store node.js sources [default: /tmp/nexe]
-f, --flags Don't parse node and v8 flags, pass through app flags [default: false] -f, --flags Don't parse node and v8 flags, pass through app flags [default: false]
```` ```
### Code Usage ### Code Usage
````javascript ```javascript
var nexe = require('nexe'); var nexe = require('nexe');
@@ -131,7 +133,12 @@ nexe.compile({
nodeTempDir: __dirname, nodeTempDir: __dirname,
flags: true flags: true
}, function(err) { }, function(err) {
}); });
```` ```
## Maintainers
* __Jared Allard__ ([@rainbowdashdc](https://github.com/RainbowDashDC)) &lt;[rainbowdashdc@mezgrman.de](mailto:rainbowdashdc@mezgrman.de)&gt; (Active)
* __Craig Jefferds__ ([@crcn](https://github.com/crcn)) &lt;[craig.j.condon@gmail.com](mailto:craig.j.condon@gmail.com)&gt; (Not Active)
+9 -4
View File
@@ -34,6 +34,11 @@ options('f', {
options('v', { options('v', {
alias: 'version', alias: 'version',
description: 'Display version number' description: 'Display version number'
}).
options('p', {
alias: 'python',
description: 'Set path of python to use.',
default: 'python'
}); });
var argv = cli.argv; var argv = cli.argv;
@@ -54,12 +59,12 @@ function toRelative(pt) {
return path.join(process.cwd(), pt); return path.join(process.cwd(), pt);
} }
require('../lib').compile({
require('../lib').compile({
input : require.resolve(toRelative(argv.i)), input : require.resolve(toRelative(argv.i)),
output : toRelative(argv.o), output : toRelative(argv.o),
flags : argv.f, flags : argv.f,
nodeVersion : argv.r, nodeVersion : argv.r,
python : argv.python,
nodeTempDir : toRelative(argv.t) }, function(error) { nodeTempDir : toRelative(argv.t) }, function(error) {
if(error) console.log(error.message); if(error) console.log(error.message);
+3 -2
View File
@@ -3,9 +3,10 @@ var nexe = require('nexe');
nexe.compile( nexe.compile(
{ {
input: "./index.js", input: "./index.js",
output: "./helloWorld.exe", output: "",
nodeVersion: "0.10.33", nodeVersion: "0.10.33",
nodeTempDir: "", nodeTempDir: "",
python: "C:\\Python27\\python.exe",
flags: true, flags: true,
resourceFiles: ["./message.txt"] resourceFiles: ["./message.txt"]
}, },
@@ -14,4 +15,4 @@ nexe.compile(
console.log(err); console.log(err);
} }
} }
); );
+73 -12
View File
@@ -19,8 +19,10 @@ var _log = require("./log"),
_monkeypatch = require("./monkeypatch"); _monkeypatch = require("./monkeypatch");
var isWin = /^win/.test(process.platform); var isWin = /^win/.test(process.platform);
var isPy;
/** /**
* Compiliation process.
*/ */
exports.compile = function (options, complete) { exports.compile = function (options, complete) {
@@ -28,11 +30,31 @@ exports.compile = function (options, complete) {
var nodeCompiler, nexeEntryPath; var nodeCompiler, nexeEntryPath;
async.waterfall([ async.waterfall([
/** check relevant options
*
*/
function checkOpts (next) {
/*
* Have we been given a custom flag for python executable?
*/
if(options.python!=='python' && options.python!=="") {
if(isWin) {
isPy=options.python.replace(/\//gm, "\\"); // use windows file paths, batch is sensitive.
} else {
isPy=options.python;
}
_log("set python as "+isPy);
} else {
isPy="python";
}
next();
},
/** /**
* first download node * first download node
*/ */
function downloadNode (next) { function downloadNode (next) {
_downloadNode(options.nodeVersion, options.nodeTempDir, next); _downloadNode(options.nodeVersion, options.nodeTempDir, next);
}, },
@@ -104,11 +126,16 @@ exports.compile = function (options, complete) {
*/ */
function makeExe (next) { function makeExe (next) {
_log("make"); if(isWin) {
_log("vcbuild [make stage]");
} else {
_log("make");
}
nodeCompiler.make(next); nodeCompiler.make(next);
}, },
/** /**
* we create the output directory if needed
*/ */
function makeOutputDirectory (next) { function makeOutputDirectory (next) {
@@ -116,11 +143,20 @@ exports.compile = function (options, complete) {
}, },
/** /**
* Copy the compilied binary to the output specified.
*/ */
function copyBinaryToOutput (next) { function copyBinaryToOutput (next) {
_log("cp %s %s", nodeCompiler.releasePath, options.output); _log("cp %s %s", nodeCompiler.releasePath, options.output);
ncp(nodeCompiler.releasePath, options.output, next); ncp(nodeCompiler.releasePath, options.output, function (err) {
if (err) {
console.log("* NOTICE * Failed to copy binary. Did the build fail?");
throw err; // dump raw error object
}
_log('copied');
next();
});
} }
], complete); ], complete);
} }
@@ -228,7 +264,27 @@ function _getNodeCompiler (nodeFileDir, complete) {
version: path.basename(nodeFileDir), version: path.basename(nodeFileDir),
releasePath: path.join(dir, "Release", "node.exe"), releasePath: path.join(dir, "Release", "node.exe"),
make: function(next) { make: function(next) {
var vcbuild = spawn("vcbuild.bat", ["nosign", "release"], { cwd: dir }); // create a new env with minimal impact on old one
var newEnv = process.env
if(isPy!=="python") {
_log("vcbuild: python => "+isPy);
// replace vcbuild contents
var data = fs.readFileSync(dir+"\\vcbuild.bat", 'utf8');
var result = data.replace(/[\s]python/gm, isPy); // I can't regex
var err = fs.writeFileSync(dir+"\\vcbuild.bat", result, 'utf8');
if(err) throw err;
// temporary fix, should edit whatever is gening the project files at somepoint.
newEnv.path = process.env.PATH+";"+path.dirname(isPy)
}
// spawn a vcbuild process with our custom enviroment.
var vcbuild = spawn("vcbuild.bat", ["nosign", "release"], {
cwd: dir,
env: newEnv
});
vcbuild.stdout.pipe(process.stdout); vcbuild.stdout.pipe(process.stdout);
vcbuild.stderr.pipe(process.stderr); vcbuild.stderr.pipe(process.stderr);
vcbuild.on("close", function() { vcbuild.on("close", function() {
@@ -242,7 +298,13 @@ function _getNodeCompiler (nodeFileDir, complete) {
version: path.basename(nodeFileDir), version: path.basename(nodeFileDir),
releasePath: path.join(dir, "out", "Release", "node"), releasePath: path.join(dir, "out", "Release", "node"),
make: function (next) { make: function (next) {
var configure = spawn("./configure", [], { cwd: dir }); var cfg = "./configure", configure;
if(isPy !== "python") {
configure = spawn(isPy, [cfg], { cwd: dir });
} else {
configure = spawn(cfg, [], { cwd: dir });
}
configure.stdout.pipe(process.stdout); configure.stdout.pipe(process.stdout);
configure.stderr.pipe(process.stderr); configure.stderr.pipe(process.stderr);
configure.on("close", function () { configure.on("close", function () {
@@ -281,7 +343,7 @@ function _monkeyPatchNodeConfig (compiler, complete) {
}, },
/** /**
* monkeypatch main entry point * monkeypatch main entry point
*/ */
function (next) { function (next) {
@@ -299,7 +361,7 @@ function _monkeyPatchGyp (compiler, complete) {
var gypPath = path.join(compiler.dir, "node.gyp"); var gypPath = path.join(compiler.dir, "node.gyp");
_monkeypatch( _monkeypatch(
gypPath, gypPath,
function (content) { function (content) {
return ~content.indexOf("nexe.js"); return ~content.indexOf("nexe.js");
}, },
@@ -317,7 +379,7 @@ function _monkeyPatchMainJs (compiler, complete) {
var mainPath = path.join(compiler.dir, "src", "node.js"); var mainPath = path.join(compiler.dir, "src", "node.js");
_monkeypatch( _monkeypatch(
mainPath, mainPath,
function (content) { function (content) {
return ~content.indexOf("nexe"); return ~content.indexOf("nexe");
}, },
@@ -395,9 +457,9 @@ function _logProgress (req) {
req.on("response", function (resp) { req.on("response", function (resp) {
var len = parseInt(resp.headers["content-length"], 10), var len = parseInt(resp.headers["content-length"], 10),
bar = new ProgressBar("[:bar]", { bar = new ProgressBar("[:bar]", {
complete: "=", complete: "=",
incomplete: " ", incomplete: " ",
total: len, total: len,
width: process.stdout.columns - 2 width: process.stdout.columns - 2
}); });
@@ -409,4 +471,3 @@ function _logProgress (req) {
return req; return req;
} }
-2
View File
@@ -1,3 +1 @@
module.exports = require("./exe"); module.exports = require("./exe");