248 lines
4.4 KiB
JavaScript
248 lines
4.4 KiB
JavaScript
var step = require("step"),
|
|
outcome = require("outcome"),
|
|
request = require("request"),
|
|
fs = require("fs"),
|
|
mkdirp = require("mkdirp"),
|
|
path = require("path"),
|
|
child_process = require("child_process"),
|
|
exec = child_process.exec,
|
|
spawn = child_process.spawn,
|
|
sprintf = require("sprintf").sprintf,
|
|
browserify = require("browserify"),
|
|
ncp = require("ncp").ncp;
|
|
|
|
/**
|
|
*/
|
|
|
|
exports.compile = function(args, next) {
|
|
|
|
var on = outcome.error(next);
|
|
|
|
args.input = require.resolve(args.input);
|
|
|
|
step(
|
|
|
|
/**
|
|
* 1. download node
|
|
*/
|
|
|
|
function() {
|
|
downloadNode(args.runtime, this);
|
|
},
|
|
|
|
/**
|
|
* 2. build the script into ONE file
|
|
*/
|
|
|
|
on.success(function(node) {
|
|
console.log("making application bundle with %s", args.input);
|
|
this.node = node;
|
|
var b = browserify();
|
|
b.addEntry(args.input);
|
|
this(null, b.bundle());
|
|
}),
|
|
|
|
/**
|
|
* 3. write the file into the node libs directory
|
|
*/
|
|
|
|
on.success(function(bundle) {
|
|
console.log("writing application bundle");
|
|
fs.writeFile(this.nexePath = path.join(this.node.dir, "lib", "nexe.js"), bundle, "utf8", this);
|
|
}),
|
|
|
|
/**
|
|
* 4. monkeypatch the node entry
|
|
*/
|
|
|
|
on.success(function() {
|
|
console.log("monkey patching node.js file");
|
|
monkeyPatchNodejs(this.node, this);
|
|
}),
|
|
|
|
/**
|
|
* 5. bundle it all together
|
|
*/
|
|
|
|
on.success(function() {
|
|
console.log("building node.js");
|
|
this.node.make(this);
|
|
}),
|
|
|
|
/**
|
|
* 6. copy the executable
|
|
*/
|
|
|
|
on.success(function() {
|
|
console.log("copying binary to output directory to %s", args.output);
|
|
|
|
mkdirp(path.dirname(args.output), this);
|
|
}),
|
|
|
|
/**
|
|
*/
|
|
|
|
function() {
|
|
ncp(this.node.releasePath, args.output, this);
|
|
},
|
|
|
|
/**
|
|
*/
|
|
|
|
next
|
|
|
|
)
|
|
}
|
|
|
|
/**
|
|
*/
|
|
|
|
function downloadNode(version, next) {
|
|
|
|
var tmpPath = path.join("/tmp/nexe", "node-v" + version + ".tar.gz"),
|
|
srcDr = tmpPath.replace(/\.tar.gz$/, "");
|
|
|
|
try {
|
|
|
|
mkdirp.sync(path.dirname(tmpPath))
|
|
|
|
//an error will usually occur when the dir already exists.
|
|
} catch(e) { }
|
|
|
|
step(
|
|
|
|
/**
|
|
* download
|
|
*/
|
|
|
|
function() {
|
|
|
|
//zip exists?
|
|
if(fs.existsSync(tmpPath) || fs.existsSync(srcDr)) return this();
|
|
|
|
console.log("downloading node %s", version);
|
|
|
|
var output = fs.createWriteStream(tmpPath, { "flags": "w+" }),
|
|
req = request("http://nodejs.org/dist/v" + version + "/node-v" + version + ".tar.gz").pipe(output);
|
|
|
|
output.on("close", this);
|
|
},
|
|
|
|
/**
|
|
* untar
|
|
*/
|
|
|
|
function() {
|
|
|
|
//source dir exists?
|
|
if(fs.existsSync(srcDr)) return this();
|
|
|
|
console.log("unzipping node source");
|
|
|
|
|
|
//TODO - use native zlib library for this
|
|
exec(sprintf("tar -xf '%s'", tmpPath), { cwd: path.dirname(tmpPath) }, this);
|
|
},
|
|
|
|
/**
|
|
* cleanup the node.js file
|
|
*/
|
|
|
|
function() {
|
|
fs.unlink(tmpfile, this);
|
|
},
|
|
|
|
/**
|
|
* return make script
|
|
*/
|
|
|
|
function() {
|
|
next(null, {
|
|
|
|
//the directory to the node.js file
|
|
dir: srcDr,
|
|
|
|
releasePath: path.join(srcDr, "out/Release/node"),
|
|
|
|
//makes node.js
|
|
make: function(next) {
|
|
var proc = exec(sprintf("cd %s; ./configure; make; ", srcDr));
|
|
proc.stdout._events = {}; //remove stdout & stdin capture
|
|
proc.stdin._events = {};
|
|
proc.stdout.on("data", function(chunk) {
|
|
process.stdout.write(chunk);
|
|
});
|
|
proc.stderr.on("data", function(chunk) {
|
|
process.stdout.write(chunk);
|
|
});
|
|
|
|
proc.on("exit", next);
|
|
}
|
|
});
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
|
|
function monkeyPatchNodejs(node, next) {
|
|
|
|
var nodejsPath = path.join(node.dir, "src", "node.js"),
|
|
nodegypPath = path.join(node.dir, "node.gyp"),
|
|
on = outcome.error(next);
|
|
|
|
step(
|
|
|
|
/**
|
|
* read the node.js file
|
|
*/
|
|
|
|
function() {
|
|
fs.readFile(nodejsPath, "utf8", this);
|
|
},
|
|
|
|
/**
|
|
* inject nexe as _eval IF it hasn't already been injected
|
|
*/
|
|
|
|
on.success(function(content) {
|
|
|
|
//nexe already injected?
|
|
if(~content.indexOf('nexe')) return this();
|
|
|
|
fs.writeFile(nodejsPath,
|
|
content.replace(/\(function\(process\) \{/,'(function(process){ \n process._eval = \'require("nexe");\'; '),
|
|
"utf8",
|
|
this);
|
|
}),
|
|
|
|
/**
|
|
* next, find node.gyp and add nexe as a native lib file
|
|
*/
|
|
|
|
on.success(function() {
|
|
fs.readFile(nodegypPath, "utf8", this);
|
|
}),
|
|
|
|
/**
|
|
* finally, monkeypatch node.gyp
|
|
*/
|
|
|
|
on.success(function(content) {
|
|
|
|
//nexe already included as dep?
|
|
if(~content.indexOf('lib/nexe.js')) return this();
|
|
|
|
fs.writeFile(nodegypPath,
|
|
content.replace("'lib/fs.js',", "'lib/fs.js', 'lib/nexe.js', "),
|
|
"utf8",
|
|
this);
|
|
}),
|
|
|
|
/**
|
|
*/
|
|
|
|
next
|
|
);
|
|
} |