Compare commits
210 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bbe26640df | |||
| 54675f0e23 | |||
| 3ac02efd18 | |||
| b100922d91 | |||
| 87660c3682 | |||
| 635cd62196 | |||
| 336a5ea2e3 | |||
| 7fe0d207de | |||
| 3e708ca916 | |||
| de84339c80 | |||
| fb81a9c75e | |||
| 0e34905ddc | |||
| c1e7416644 | |||
| 53daa903ea | |||
| 9e2a5f1c78 | |||
| 82a6e8f1c7 | |||
| 7641afa5a4 | |||
| 34210a3bd6 | |||
| 6ce224d6e4 | |||
| 53a9c5a210 | |||
| 727f081e87 | |||
| 907be00fdc | |||
| 14d1ec38d1 | |||
| de531ba750 | |||
| a497851a74 | |||
| 915181d0b0 | |||
| 002727e10f | |||
| a9aa1f81fa | |||
| 16139e1dc7 | |||
| 2bc181f2ab | |||
| 4c80d88013 | |||
| 36094e8d47 | |||
| af42599a15 | |||
| 78ca929350 | |||
| 024b9f8cb3 | |||
| 312a63a0b6 | |||
| 995e03eeea | |||
| b803ae7ddd | |||
| d2e954b5ab | |||
| ec421204d0 | |||
| 292063c482 | |||
| a0a82e9547 | |||
| e1b30b86ae | |||
| 4c88a01003 | |||
| 5dbd6b4048 | |||
| ce6c570c01 | |||
| 44581eb3d3 | |||
| d4be3712cd | |||
| 882c838cb5 | |||
| e6e49bbbd9 | |||
| 0ae40b9a3c | |||
| 879b1598bc | |||
| 5c40ca30af | |||
| afb143daf4 | |||
| 3dd5a2102f | |||
| 2cfd10261a | |||
| e7c7878675 | |||
| 3b42e4a5e8 | |||
| c9431fc206 | |||
| dd68923607 | |||
| 8901e4a2fa | |||
| 38a920be24 | |||
| ce7a36958f | |||
| b0644f0d62 | |||
| 4e402bf937 | |||
| 5a3bbbad3a | |||
| 1d14ca6359 | |||
| 1114a581ae | |||
| 7ab7f986cf | |||
| 1d09a6b001 | |||
| 636268504e | |||
| e8dead82bb | |||
| d2d703e9ea | |||
| 09f36c48e0 | |||
| 6e2870e5d0 | |||
| cd0e5a012c | |||
| 17fe557afa | |||
| e4a8d86237 | |||
| 7b3bcac07c | |||
| fb637e0da3 | |||
| 17c506c9cc | |||
| 7a25c2bfd9 | |||
| f784c79ca1 | |||
| bd75617a2a | |||
| b7ffb8266a | |||
| 08b7ad765d | |||
| 3a7eb91d3b | |||
| a0017ed3fe | |||
| d4205a70c3 | |||
| 380b0e9541 | |||
| 86fa69920c | |||
| 3144ae8d6f | |||
| 322f432756 | |||
| dcf44f7a80 | |||
| 7b68d7bfee | |||
| 1684c8fe5d | |||
| 2c132110b9 | |||
| cf97acfcdb | |||
| a1405a3b36 | |||
| 6c844fa5f7 | |||
| a40454a5ae | |||
| 94c5a54d5f | |||
| 99e228a145 | |||
| 564dffe925 | |||
| 7b9f235715 | |||
| e7b28d0aa5 | |||
| bc37c3ce7b | |||
| 87c5e1df7d | |||
| 05ecc6b8a5 | |||
| e89844fa78 | |||
| 0637e17eb0 | |||
| c8562c384d | |||
| c07e1d62c7 | |||
| ec60175d8f | |||
| 81192a7b3a | |||
| 029487c187 | |||
| 71eef791c6 | |||
| e1eaaa2bfc | |||
| 7ef54aa56f | |||
| c09bca3462 | |||
| 552158485c | |||
| 553d9a2fff | |||
| fcd2acfed6 | |||
| 5c20233ba5 | |||
| 3a74fddcf6 | |||
| 839741d36f | |||
| 9080b05b72 | |||
| de0a2cd517 | |||
| 0f038b1de1 | |||
| d7a909da71 | |||
| aeeb24c757 | |||
| 3cc7c68b12 | |||
| 9247016635 | |||
| bc4f50f69b | |||
| 8a0121023e | |||
| 7308d9665d | |||
| 95afa87f71 | |||
| adff5a3a7c | |||
| 9f86d88ec5 | |||
| fd01aac2e7 | |||
| 9d372ffecd | |||
| 5148a0b980 | |||
| a20406b427 | |||
| f74a47f483 | |||
| 1e982d0e82 | |||
| 7fd13d837c | |||
| 932db9813d | |||
| a0202559bc | |||
| c9025d1c74 | |||
| fb57b09e66 | |||
| 9742681c09 | |||
| ca3ab97bee | |||
| 078540697c | |||
| c583e2f029 | |||
| 5a7a7c9fe5 | |||
| 0868535bbe | |||
| 2164621498 | |||
| 2683359460 | |||
| 94a82867fe | |||
| a91d0428df | |||
| 1dee735cdb | |||
| ed36ebb795 | |||
| 10af1803ab | |||
| 9f93ac0e1e | |||
| 66bde4c761 | |||
| 3803fdaf15 | |||
| 847616a295 | |||
| 085e475bd4 | |||
| 273e864e07 | |||
| 46b2761db8 | |||
| 254615894f | |||
| 1aa897e132 | |||
| 8552619bc5 | |||
| 9007a080cf | |||
| 46503af805 | |||
| 758803540b | |||
| 424a7bdcbb | |||
| d44199e592 | |||
| 7d783ced63 | |||
| 85b9250b9a | |||
| b2871f09cd | |||
| 6ff539b4e6 | |||
| e8ea712a45 | |||
| c3c1ddaaf0 | |||
| b89f9650c5 | |||
| b78cea8c35 | |||
| ddea854649 | |||
| 0281273cd0 | |||
| 336a30e7c0 | |||
| 4f9c040d74 | |||
| cdbdbfbb0d | |||
| 63ba6a307b | |||
| bea9181be6 | |||
| 6a62ea8f10 | |||
| f1a0eb88fd | |||
| e43a473559 | |||
| 207e381309 | |||
| 14005e70d9 | |||
| d6b65478ce | |||
| 11aaccdf66 | |||
| 45dd2d2680 | |||
| a1a06e310c | |||
| 716d947914 | |||
| 5076c15e76 | |||
| 2995a3d916 | |||
| d0e259be6f | |||
| b2f621d7d0 | |||
| a2f6492d71 | |||
| c8aa6a8326 | |||
| 9b82355175 |
+12
@@ -0,0 +1,12 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
*.nex
|
||||
src
|
||||
nexe.exe
|
||||
nexe
|
||||
npm-debug.log
|
||||
test/**/src
|
||||
test/**/out.nex
|
||||
test/**/test.nex
|
||||
test/**/tmp
|
||||
test/**/node_modules
|
||||
@@ -0,0 +1,59 @@
|
||||
# Nexe ChangeLog
|
||||
|
||||
## 2015-02-20, Version v0.3.7, @jaredallard
|
||||
|
||||
### Noteable Changes
|
||||
|
||||
* Fixed #103.
|
||||
* Made not-available require not a fatal error.
|
||||
* Stub and system to ignore certain requires.
|
||||
* Added 'sys' to ignore list.
|
||||
* We have a gitter!
|
||||
* Gave win32 a 100 length progress bar.
|
||||
|
||||
### Commits
|
||||
|
||||
* [**2cacd83**] Update README.md (@crcn)
|
||||
* [**0e90ac9**] Update README.md (@crcn)
|
||||
* [**54967d1**] Added Gitter badge (@jaredallard)
|
||||
* [**bb489a3**] Fixes #98 by giving win32 a 100 length progress bar. (@jaredallard)
|
||||
* [**39665a8**] Lighter weight way to accomplish the exclusion of the sys module (@CKarper)
|
||||
* [**5aca22d**] This handles embedding 'bin' scripts with shebang interpreter... (@CKarper)
|
||||
* [**e79b0fb**] Stub to ignore require('sys') (@CKarper)
|
||||
|
||||
## 2015-02-15, Version v0.3.6, @jaredallard
|
||||
|
||||
### Noteable Changes
|
||||
|
||||
* Now support .json in require.
|
||||
* Fixed a major --python flag bug.
|
||||
|
||||
### Commits
|
||||
|
||||
* [**cac6986**] V bump to solve critical error. (@jaredallard)
|
||||
* [**b040337**] Fixes #99, resolves #97 by warning on missing file. New examples... (@jaredallard)
|
||||
* [**ad4da1d**] Support .json extensions in require() resolution (@CKarper)
|
||||
|
||||
## 2015-02-14, Version v0.3.5, @jaredallard
|
||||
|
||||
|
||||
### Noteable Changes
|
||||
|
||||
* Added new flag: `--python </path/to/python>`
|
||||
* Added resourceFiles option which allows embedding files and getting them via embed.js
|
||||
* Updated a bunch of the dependencies.
|
||||
* `process.argv` is now consistent in a child fork case.
|
||||
* Added `child_process.fork` support.
|
||||
* Added new collaborators:
|
||||
* Jared Allard (@jaredallard)
|
||||
|
||||
### Commits
|
||||
|
||||
* [**e4155c8**] Version bump 0.3.5, update depends (@jaredallard)
|
||||
* [**e91f5b5**] Add example, fix outdated examples (@jaredallard)
|
||||
* [**3b1d5a9**] Modify README, implement cross-plat `--python <loc>` closes #94 (@jaredallard)
|
||||
* [**29d5f6a**] Make `process.argv` consistent in the child fork case (@LorenzGardner)
|
||||
* [**97dbd37**] Add support for embedded files. (@LorenzGardner)
|
||||
* [**b615e12**] Make the example code demonstrate forked process and dynamic require (@LorenzGardner)
|
||||
* [**333cc69**] update read me mentioning usage of `child_process.fork` (@LorenzGardner)
|
||||
* [**ece4b2d**] Add `child_process.fork` support. (@LorenzGardner)
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2013 Craig Condon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,58 +1,186 @@
|
||||
Compile javascript **with** node.js. This allows you to move your executable around *without* needing to install the node.js runtime.
|
||||
### Nexe
|
||||
|
||||
## Requirements
|
||||
[](https://gitter.im/jaredallard/nexe?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://david-dm.org/crcn/nexe)
|
||||
[](http://waffle.io/jaredallard/nexe)
|
||||
|
||||
- Linux / Mac
|
||||
Nexe is a command-line utility that compiles your Node.js application into a single executable file.
|
||||
|
||||

|
||||
|
||||
|
||||
### Motivation
|
||||
|
||||
- Ability to run multiple applications with *different* node.js runtimes.
|
||||
- Distributable binaries without needing node / npm.
|
||||
- Starts faster.
|
||||
- Lockdown specific application versions, and easily rollback.
|
||||
- Faster deployments.
|
||||
|
||||
## Building Requirements
|
||||
|
||||
- Linux / Mac / BSD / Windows
|
||||
- Python 2.6 or 2.7 (use --python if not in PATH)
|
||||
- Windows: Visual Studio 2010+
|
||||
|
||||
## Caveats
|
||||
|
||||
### Doesn't support native modules
|
||||
|
||||
- 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 statements
|
||||
|
||||
Such As:
|
||||
|
||||
```javascript
|
||||
var x = require(someVar);
|
||||
```
|
||||
|
||||
In this case nexe won't bundle the file
|
||||
|
||||
```javascript
|
||||
var x;
|
||||
if (someCheck) {
|
||||
x = require("./ver1.js");
|
||||
} else {
|
||||
x = require("./var2.js");
|
||||
}
|
||||
```
|
||||
|
||||
In this case nexe will bundle both files.
|
||||
|
||||
Workarounds:
|
||||
1) for dynamic requires that you want bundled add the following into your project
|
||||
|
||||
```javascript
|
||||
var dummyToForceIncludeForBundle = false;
|
||||
if (dummyToForceIncludeForBundle) {
|
||||
require("./loadedDynamicallyLater.js");
|
||||
// ...
|
||||
}
|
||||
```
|
||||
this will trick the bundler into including them.
|
||||
|
||||
2) for dynamic files getting included that you don't want to be
|
||||
|
||||
```javascript
|
||||
var moduleName = "./ver2.js";
|
||||
if (someCheck) {
|
||||
moduleName = "./ver1.js";
|
||||
}
|
||||
var x = require(moduleName);
|
||||
```
|
||||
Note: neither file will be bundled.
|
||||
|
||||
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.
|
||||
|
||||
### __dirname
|
||||
|
||||
Once the module is bundled it is part of the executable. __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.
|
||||
|
||||
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"));
|
||||
```
|
||||
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 dependency that you are unaware of).
|
||||
|
||||
Note: __filename will be 'undefined'
|
||||
|
||||
### child_process.fork
|
||||
|
||||
child_process.spawn works is unmodified, but child_process.fork will make an attempt to launch a new instance of your executable and run the bundled module.
|
||||
|
||||
## Installation
|
||||
|
||||
Via NPM:
|
||||
|
||||
```bash
|
||||
npm install nexe
|
||||
npm install nexe [-g]
|
||||
```
|
||||
|
||||
Or git:
|
||||
|
||||
```bash
|
||||
git clone
|
||||
git clone https://github.com/crcn/nexe.git
|
||||
```
|
||||
|
||||
|
||||
### Motivation
|
||||
|
||||
- Developing client-side utilities without requiring to install a bunch of dependencies first (node.js, npm).
|
||||
- Ability to run multiple node.js applications with *different* node.js runtimes.
|
||||
|
||||
|
||||
### CLI Usage
|
||||
|
||||
````text
|
||||
|
||||
Commands:
|
||||
-i the input javascript files
|
||||
-o the output executable
|
||||
--runtime the runtime version of node.js to compile with
|
||||
```text
|
||||
|
||||
Examples:
|
||||
-i input.js -o my-binary --runtime=0.6.2 compile javascript file with node
|
||||
Usage: nexe -i [sources] -o [binary] [options]
|
||||
|
||||
````
|
||||
Options:
|
||||
-i, --input The entry javascript files [default: cwd]
|
||||
-o, --output The output binary [default: out.nex]
|
||||
-r, --runtime The node.js runtime to use [default: "latest"]
|
||||
-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]
|
||||
-v, --version Display version number
|
||||
-p, --python Set path of python to use. [default: "python"]
|
||||
-F, --framework Set the framework to use. [default: "nodejs"]
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Code usage
|
||||
### Code Usage
|
||||
|
||||
````javascript
|
||||
```javascript
|
||||
|
||||
var nexe = require('nexe');
|
||||
var nexe = require('nexe');
|
||||
|
||||
nexe.compile('input.js', 'output.bin', function() {
|
||||
|
||||
});
|
||||
|
||||
````
|
||||
nexe.compile({
|
||||
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) {
|
||||
if(err) {
|
||||
return console.log(err);
|
||||
}
|
||||
|
||||
// do whatever
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### package.json inclusion
|
||||
|
||||
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^$",
|
||||
"temp": "src",
|
||||
"runtime": {
|
||||
"framework": "node",
|
||||
"version": "5.5.0",
|
||||
"js-flags": "--use_strict",
|
||||
"ignoreFlags": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
* output: can use ^$ for platform specific file extension
|
||||
* js-flags: this is also known as v8 flags, and supports *all* v8 flags.
|
||||
|
||||
## Maintainers
|
||||
|
||||
* __Jared Allard__ ([@jaredallard](https://github.com/jaredallard)) <[jaredallard@outlook.com](mailto:jaredallard@outlook.com)> (Active)
|
||||
* __Christopher Karper__ ([@ckarper](https://github.com/CKarper)) <[Christopher.Karper@gmail.com](mailto:Christopher.Karper@gmail.com)> (Active)
|
||||
* __Craig Condon__ ([@crcn](https://github.com/crcn)) <[craig.j.condon@gmail.com](mailto:craig.j.condon@gmail.com)> (Old Project Owner)
|
||||
|
||||
@@ -1,2 +1,96 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
nexe = require('../lib'),
|
||||
_log = require("../lib/log"),
|
||||
cli = require('yargs').
|
||||
usage('Usage: $0 -i [sources] -o [binary]').
|
||||
options('i', {
|
||||
demand: true,
|
||||
alias: 'input',
|
||||
desc: 'The entry javascript files',
|
||||
default: process.cwd()
|
||||
}).
|
||||
options('o', {
|
||||
demand: true,
|
||||
alias: 'output',
|
||||
desc: 'The output binary',
|
||||
default: "out.nex"
|
||||
}).
|
||||
options('r', {
|
||||
alias: 'runtime',
|
||||
default: 'latest',
|
||||
description: 'The node.js runtime to use'
|
||||
}).
|
||||
options('t', {
|
||||
alias: 'temp',
|
||||
default: './tmp/nexe',
|
||||
description: 'The path to store node.js sources'
|
||||
}).
|
||||
options('f', {
|
||||
alias: 'flags',
|
||||
description: 'Don\'t parse node and v8 flags, pass through app flags',
|
||||
default: false
|
||||
}).
|
||||
options('v', {
|
||||
alias: 'version',
|
||||
description: 'Display version number'
|
||||
}).
|
||||
options('p', {
|
||||
alias: 'python',
|
||||
description: 'Set path of python to use.',
|
||||
default: 'python'
|
||||
}).
|
||||
options('F', {
|
||||
alias: 'framework',
|
||||
description: 'Set the framework to use',
|
||||
default: 'nodejs'
|
||||
});
|
||||
|
||||
var argv = cli.argv;
|
||||
if(argv.h || argv.help) {
|
||||
cli.showHelp();
|
||||
process.exit();
|
||||
} else if (argv.v || argv.version) {
|
||||
var pkginfo = require('../package.json');
|
||||
console.log(pkginfo.version);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Support network shares?
|
||||
**/
|
||||
function toAbsolute(pt) {
|
||||
if(pt.substr(0, 1) == "/") return pt;
|
||||
if(pt.substr(1, 3) == ":/") return pt; // for windows "c:/"
|
||||
return path.join(process.cwd(), pt);
|
||||
}
|
||||
|
||||
if(fs.lstatSync(argv.i).isDirectory()) {
|
||||
opts = nexe.package(path.join(argv.i, "package.json"), argv);
|
||||
nexe.compile(opts, function(error) {
|
||||
if(error) {
|
||||
return console.log(error.message);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
/**
|
||||
* Call the core
|
||||
**/
|
||||
nexe.compile({
|
||||
input : require.resolve(toAbsolute(argv.i)),
|
||||
output : toAbsolute(argv.o),
|
||||
flags : argv.f,
|
||||
nodeVersion : argv.r,
|
||||
python : argv.python,
|
||||
nodeTempDir : toAbsolute(argv.t),
|
||||
framework : argv.F
|
||||
},
|
||||
function(error) {
|
||||
if(error) {
|
||||
return console.log(error.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**/
|
||||
|
||||
var mdeps = require("module-deps"),
|
||||
path = require("path"),
|
||||
spawn = require('child_process').spawn,
|
||||
fs = require("fs"),
|
||||
async = require("async"),
|
||||
browserify = require('browserify'),
|
||||
builtins = require("builtins"),
|
||||
_log = require("./log");
|
||||
|
||||
/**
|
||||
* User browserify to create a "packed" file.
|
||||
*
|
||||
* @param {String} input - input file
|
||||
* @param {String} nc - node compiler dir
|
||||
* @param {Function} complete - next function to call (async)
|
||||
**/
|
||||
function bundle (input, nc, complete) {
|
||||
var bundlePath = path.join(nc, "lib", "nexe.js");
|
||||
var ws = fs.createWriteStream(bundlePath);
|
||||
var browserifyExec;
|
||||
|
||||
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);
|
||||
|
||||
proc.on('error', function(err) {
|
||||
console.error(err.toString('ascii'));
|
||||
_log('error', 'Failed to invoke browserify');
|
||||
process.exit(1);
|
||||
})
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
proc.on('close', function(code) {
|
||||
_log("Browserify finished");
|
||||
})
|
||||
|
||||
ws.on('error', function(err) {
|
||||
console.log(err);
|
||||
_log('error', 'Failed to save stdout to disk');
|
||||
process.exit(1);
|
||||
})
|
||||
|
||||
ws.on('close', function() {
|
||||
var source = fs.readFileSync(bundlePath, 'utf8');
|
||||
source = source.replace(/[^\x00-\x7F]/g, "");
|
||||
|
||||
// write the source modified to nexe.js
|
||||
fs.writeFile(bundlePath, source, 'utf8', function(err) {
|
||||
if(err) {
|
||||
_log('error', 'failed to save source');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = bundle;
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**/
|
||||
|
||||
var path = require("path"),
|
||||
fs = require("fs");
|
||||
|
||||
/**
|
||||
* TODO: Optimize this code. (more like document it so I understand it better.)
|
||||
**/
|
||||
function embed(resourceFiles, resourceRoot, complete) {
|
||||
function encode(filePath) {
|
||||
return fs.readFileSync(filePath).toString('base64');
|
||||
}
|
||||
|
||||
resourceFiles = resourceFiles || [];
|
||||
resourceRoot = resourceRoot || "";
|
||||
|
||||
if (!Array.isArray(resourceFiles)) {
|
||||
throw new Error("Bad Argument: resourceFiles is not an array");
|
||||
}
|
||||
|
||||
var buffer = "var embeddedFiles = {\n";
|
||||
for (var i = 0; i < resourceFiles.length; ++i) {
|
||||
buffer += JSON.stringify(path.relative(resourceRoot, resourceFiles[i])) + ': "';
|
||||
buffer += encode(resourceFiles[i]) + '",\n';
|
||||
}
|
||||
|
||||
buffer += "\n};\n\nmodule.exports.keys = function () { return Object.keys(embeddedFiles); }\n\nmodule.exports.get = ";
|
||||
buffer += accessor.toString();
|
||||
complete(null, buffer);
|
||||
}
|
||||
|
||||
var accessor = function (key) {
|
||||
if (embeddedFiles.hasOwnProperty(key)) {
|
||||
return new Buffer(embeddedFiles[key], 'base64');
|
||||
}
|
||||
else {
|
||||
//file was not embedded, throw err.
|
||||
throw new Error('Embedded file not found');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = embed;
|
||||
+879
@@ -0,0 +1,879 @@
|
||||
/**
|
||||
* 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
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**/
|
||||
var async = require("async"),
|
||||
outcome = require("outcome"),
|
||||
mkdirp = require("mkdirp"),
|
||||
request = require("request"),
|
||||
path = require("path"),
|
||||
fs = require("fs"),
|
||||
colors = require('colors'),
|
||||
ncp = require("ncp").ncp,
|
||||
ProgressBar = require("progress"),
|
||||
child_process = require("child_process"),
|
||||
glob = require("glob"),
|
||||
bundle = require("./bundle"),
|
||||
embed = require("./embed"),
|
||||
os = require("os"),
|
||||
targz = require('tar.gz'),
|
||||
_log = require("./log"),
|
||||
_monkeypatch = require("./monkeypatch"),
|
||||
spawn = child_process.spawn;
|
||||
|
||||
var isWin = /^win/.test(process.platform);
|
||||
var isPy;
|
||||
var framework;
|
||||
var version;
|
||||
|
||||
var option_list = [
|
||||
"python",
|
||||
"input",
|
||||
"output",
|
||||
"nodeTempDir",
|
||||
"flags",
|
||||
"framework",
|
||||
"nodeConfigureArgs",
|
||||
"nodeMakeArgs",
|
||||
"nodeVersion"
|
||||
]
|
||||
|
||||
/**
|
||||
* Compiliation process.
|
||||
*/
|
||||
|
||||
exports.compile = function (options, complete) {
|
||||
|
||||
var nodeCompiler, nexeEntryPath;
|
||||
|
||||
async.waterfall([
|
||||
/**
|
||||
*check relevant options
|
||||
*/
|
||||
function checkOpts (next) {
|
||||
/* failsafe */
|
||||
if(options === undefined) {
|
||||
_log("error", "no options given to .compile()");
|
||||
process.exit()
|
||||
}
|
||||
|
||||
/* 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?
|
||||
**/
|
||||
if(options.python!=='python' && options.python!==""
|
||||
&& options.python!==undefined) {
|
||||
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";
|
||||
}
|
||||
|
||||
// remove dots
|
||||
options.framework = options.framework.replace(/\./g, "");
|
||||
|
||||
// set outter-scope framework variable.
|
||||
framework = options.framework;
|
||||
_log("framework => "+framework);
|
||||
|
||||
version = options.nodeVersion; // better framework vc
|
||||
|
||||
// check iojs version
|
||||
if (framework === "iojs" && version === "latest" ) {
|
||||
_log("fetching iojs versions");
|
||||
mkdirp(options.nodeTempDir); // make temp dir, probably repetive.
|
||||
|
||||
// create write stream so we have control over events
|
||||
var output = fs.createWriteStream(path.join(options.nodeTempDir,
|
||||
"iojs-versions.json"));
|
||||
|
||||
request.get("https://iojs.org/dist/index.json")
|
||||
.pipe(output);
|
||||
|
||||
output.on('close', function() {
|
||||
_log("done");
|
||||
var f = fs.readFileSync(path.join(options.nodeTempDir,
|
||||
"iojs-versions.json"));
|
||||
f = JSON.parse(f);
|
||||
version = f[0].version.replace("v", "");
|
||||
|
||||
_log("iojs latest => "+version);
|
||||
|
||||
// continue down along the async road
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* first download node
|
||||
*/
|
||||
function downloadNode (next) {
|
||||
_downloadNode(version, options.nodeTempDir, options.nodeConfigureArgs, options.nodeMakeArgs, next);
|
||||
},
|
||||
|
||||
/**
|
||||
* bundle the application into one script
|
||||
*/
|
||||
|
||||
function combineProject (nc, next) {
|
||||
nodeCompiler = nc;
|
||||
_log("bundle %s", options.input);
|
||||
bundle(options.input, nodeCompiler.dir, next);
|
||||
},
|
||||
|
||||
function embedResources(next) {
|
||||
_log("embedResources %s", options.resourceFiles);
|
||||
embed(options.resourceFiles, options.resourceRoot, next);
|
||||
},
|
||||
|
||||
function writeResources (resources, next) {
|
||||
resourcePath = path.join(nodeCompiler.dir, "lib", "nexeres.js");
|
||||
_log("resource -> %s", resourcePath);
|
||||
|
||||
fs.writeFile(resourcePath, resources, next);
|
||||
},
|
||||
|
||||
/**
|
||||
* monkeypatch some files so that the nexe.js file is loaded when the app runs
|
||||
*/
|
||||
|
||||
function monkeyPatchNodeConfig (next) {
|
||||
_monkeyPatchNodeConfig(nodeCompiler, next);
|
||||
},
|
||||
|
||||
/**
|
||||
* monkeypatch node.cc to prevent v8 and node from processing CLI flags
|
||||
*/
|
||||
function monkeyPatchNodeCc (next) {
|
||||
if (options.flags) {
|
||||
_monkeyPatchMainCc(nodeCompiler, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
},
|
||||
|
||||
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
|
||||
*/
|
||||
function monkeyPatchChildProc(next) {
|
||||
_monkeyPatchChildProcess(nodeCompiler, next);
|
||||
},
|
||||
|
||||
/**
|
||||
* If an old compiled executable exists in the Release directory, delete it.
|
||||
* This lets us see if the build failed by checking the existence of this file later.
|
||||
*/
|
||||
|
||||
function cleanUpOldExecutable (next) {
|
||||
fs.unlink(nodeCompiler.releasePath, function (err) {
|
||||
if (err) {
|
||||
if (err.code === "ENOENT") {
|
||||
next();
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* compile the node application
|
||||
*/
|
||||
|
||||
function makeExecutable (next) {
|
||||
if(isWin) {
|
||||
_log("vcbuild [make stage]");
|
||||
} else {
|
||||
_log("make");
|
||||
}
|
||||
nodeCompiler.make(next);
|
||||
},
|
||||
|
||||
/**
|
||||
* we create the output directory if needed
|
||||
*/
|
||||
|
||||
function makeOutputDirectory (next) {
|
||||
mkdirp(path.dirname(options.output), function(){ next(); });
|
||||
},
|
||||
|
||||
/**
|
||||
* Verify that the executable was compiled successfully
|
||||
*/
|
||||
|
||||
function checkThatExecutableExists (next) {
|
||||
fs.exists(nodeCompiler.releasePath, function (exists) {
|
||||
if (!exists) {
|
||||
_log("error",
|
||||
"The release executable has not been generated. " +
|
||||
"This indicates a failure in the build process. " +
|
||||
"There is likely additional information above."
|
||||
);
|
||||
process.exit(1);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the compilied binary to the output specified.
|
||||
*/
|
||||
|
||||
function copyBinaryToOutput (next) {
|
||||
_log("cp %s %s", nodeCompiler.releasePath, options.output);
|
||||
ncp(nodeCompiler.releasePath, options.output, function (err) {
|
||||
if (err) {
|
||||
_log("error", "Couldn't copy binary.");
|
||||
throw err; // dump raw error object
|
||||
}
|
||||
_log('copied');
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
], complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a version of node
|
||||
*
|
||||
* @param {string} version, version of node to download
|
||||
* @param {string} directory, where to store the downloaded src
|
||||
* @param {function} complete, callback
|
||||
*/
|
||||
|
||||
function _downloadNode(version, directory, nodeConfigureArgs, nodeMakeArgs, complete) {
|
||||
var nodeFileDir = path.resolve(path.join(directory, framework, version)), // fixes #107, was process.cwd(), + rest.
|
||||
nodeFilePath = path.resolve(path.join(nodeFileDir, framework + "-" + version + ".tar.gz"));
|
||||
|
||||
|
||||
// might already be downloaded, and unzipped
|
||||
if (_getNodeCompiler(nodeFileDir, nodeConfigureArgs, nodeMakeArgs, complete)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
async.waterfall([
|
||||
|
||||
/**
|
||||
* first make the directory where the zip file will live
|
||||
*/
|
||||
|
||||
function makeDirectory (next) {
|
||||
mkdirp.sync(path.dirname(nodeFilePath));
|
||||
next();
|
||||
},
|
||||
|
||||
/**
|
||||
* download node into the target directory
|
||||
*/
|
||||
|
||||
function downloadNode (next) {
|
||||
if (fs.existsSync(nodeFilePath)) return next();
|
||||
|
||||
var uri = framework;
|
||||
|
||||
if(framework==="node") {
|
||||
uri = 'nodejs'; // if node, use nodejs uri
|
||||
} else if(framework === 'nodejs') {
|
||||
framework = 'node'; // support nodejs, and node, as framework.
|
||||
}
|
||||
|
||||
var type = global.type;
|
||||
var url, prefix = "https://"+uri+".org/dist";
|
||||
|
||||
if (version === "latest") {
|
||||
url = prefix + "/" + framework + "-" + version + ".tar.gz";
|
||||
} else {
|
||||
url = prefix + "/v" + version + "/"+framework+"-v" + version + ".tar.gz";
|
||||
}
|
||||
|
||||
_log("downloading %s", url);
|
||||
|
||||
var output = fs.createWriteStream(nodeFilePath, { "flags": "w+" });
|
||||
|
||||
// need to set user-agent to bypass some corporate firewalls
|
||||
var requestOptions = {
|
||||
url: url,
|
||||
headers: {
|
||||
"User-Agent": "Node.js"
|
||||
}
|
||||
}
|
||||
|
||||
_logProgress(request(requestOptions)).pipe(output);
|
||||
|
||||
output.on("close", function () { next(); });
|
||||
},
|
||||
|
||||
/**
|
||||
* unzip in the same directory
|
||||
*/
|
||||
|
||||
function unzipNodeTarball (next) {
|
||||
if(isWin) {
|
||||
_log("Extracting the .tar.gz.");
|
||||
new targz().extract(nodeFilePath, nodeFileDir, next);
|
||||
} else {
|
||||
var cmd = ["tar", "-xf", nodeFilePath, "-C", nodeFileDir];
|
||||
_log(cmd.join(" "));
|
||||
|
||||
var tar = spawn(cmd.shift(), cmd);
|
||||
tar.stdout.pipe(process.stdout);
|
||||
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);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* return the compiler object for the node version
|
||||
*/
|
||||
|
||||
function (next, type) {
|
||||
_getNodeCompiler(nodeFileDir, nodeConfigureArgs, nodeMakeArgs, next, type)
|
||||
},
|
||||
|
||||
], complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the compilier we will use for whatever platform we may be on and configure
|
||||
* it.
|
||||
*/
|
||||
|
||||
function _getNodeCompiler (nodeFileDir, nodeConfigureArgs, nodeMakeArgs, complete, type) {
|
||||
var dir = _getFirstDirectory(nodeFileDir);
|
||||
|
||||
// standard
|
||||
var executable = "node.exe";
|
||||
var binary = "node";
|
||||
|
||||
// iojs specifics.
|
||||
if(framework === "iojs") {
|
||||
executable = "iojs.exe";
|
||||
binary = "iojs";
|
||||
}
|
||||
|
||||
if (dir) {
|
||||
if(isWin) {
|
||||
complete(null, {
|
||||
dir: dir,
|
||||
version: path.basename(nodeFileDir),
|
||||
releasePath: path.join(dir, "Release", executable),
|
||||
make: function(next) {
|
||||
// create a new env with minimal impact on old one
|
||||
var newEnv = process.env
|
||||
|
||||
if(isPy!=="python") {
|
||||
// add the dir of the suposed python exe to path
|
||||
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.stderr.pipe(process.stderr);
|
||||
vcbuild.on("close", function() {
|
||||
next();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
complete(null, {
|
||||
dir: dir,
|
||||
version: path.basename(nodeFileDir),
|
||||
releasePath: path.join(dir, "out", "Release", binary),
|
||||
make: function (next) {
|
||||
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) {
|
||||
/* eventually try every python file */
|
||||
var pdir = fs.readdirSync(dir);
|
||||
|
||||
pdir.forEach(function(v, i) {
|
||||
var stat = fs.statSync(dir+"/"+v);
|
||||
if(stat.isFile()) {
|
||||
// only process Makefiles and .mk targets.
|
||||
if(v !== "Makefile" && path.extname(v) !== ".mk") {
|
||||
return;
|
||||
}
|
||||
|
||||
_log("patching "+v);
|
||||
|
||||
/* patch the file */
|
||||
var py = fs.readFileSync(dir+"/"+v, {encoding: 'utf8'});
|
||||
py = py.replace(/([a-z]|\/)*python(\w|)/gm, isPy); // this is definently needed
|
||||
fs.writeFileSync(dir+"/"+v, py, {encoding: 'utf8'}); // write to file
|
||||
|
||||
delete pv;
|
||||
} else if(stat.isDirectory()) {
|
||||
// must be dir?
|
||||
// skip tests because we don't need them here
|
||||
if(v !== "test") {
|
||||
_loop(dir+"/"+v)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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") {
|
||||
/**
|
||||
* Originally I thought this only applied to io.js,
|
||||
* however I soon found out this affects node.js,
|
||||
* so it is now mainstream.
|
||||
*/
|
||||
_log("preparing python");
|
||||
|
||||
// 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();
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
function _monkeyPatchNodeConfig (compiler, complete) {
|
||||
async.waterfall([
|
||||
/**
|
||||
* monkeypatch the gyp file to include the nexe.js and nexeres.js files
|
||||
*/
|
||||
function (next) {
|
||||
_monkeyPatchGyp(compiler, next)
|
||||
},
|
||||
|
||||
/**
|
||||
* monkeypatch main entry point
|
||||
*/
|
||||
function (next) {
|
||||
_monkeyPatchMainJs(compiler, next)
|
||||
}
|
||||
], complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* patch the gyp file to allow our custom includes
|
||||
*/
|
||||
|
||||
function _monkeyPatchGyp (compiler, complete) {
|
||||
|
||||
var gypPath = path.join(compiler.dir, "node.gyp");
|
||||
|
||||
_monkeypatch(
|
||||
gypPath,
|
||||
function (content) {
|
||||
return ~content.indexOf("nexe.js");
|
||||
},
|
||||
function (content, next) {
|
||||
next(null, content.replace("'lib/fs.js',", "'lib/fs.js', 'lib/nexe.js', 'lib/nexeres.js', "))
|
||||
},
|
||||
complete
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
function _monkeyPatchMainJs (compiler, complete) {
|
||||
var mainPath = path.join(compiler.dir, "src", "node.js");
|
||||
|
||||
_monkeypatch(
|
||||
mainPath,
|
||||
function (content) {
|
||||
return ~content.indexOf("nexe");
|
||||
},
|
||||
function (content, next) {
|
||||
next(null, content.replace(/\(function\(process\) \{/,'\
|
||||
(function(process) {\n\
|
||||
process._eval = \'require("nexe");\';\n\
|
||||
if (process.argv[1] !== "nexe.js") {\n\
|
||||
process.argv.splice(1, 0, "nexe.js");\n\
|
||||
}\n\
|
||||
'))
|
||||
},
|
||||
complete
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function _monkeyPatchChildProcess(compiler, complete) {
|
||||
var childProcPath = path.join(compiler.dir, "lib", "child_process.js");
|
||||
|
||||
_monkeypatch(
|
||||
childProcPath,
|
||||
function (content) {
|
||||
return ~content.indexOf("--child_process");
|
||||
},
|
||||
function (content, next) {
|
||||
next(null, content.replace(/return spawn\(/, 'args.unshift("nexe.js", "--child_process");\n return spawn('));
|
||||
},
|
||||
complete
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch node.cc to not check the internal arguments.
|
||||
*/
|
||||
|
||||
function _monkeyPatchMainCc(compiler, complete) {
|
||||
var mainPath = path.join(compiler.dir, "src", "node.cc");
|
||||
_monkeypatch(
|
||||
mainPath,
|
||||
function (content) {
|
||||
return ~content.indexOf('// // TODO use parse opts');
|
||||
},
|
||||
function (content, next) {
|
||||
var lines = content.split('\n');
|
||||
var endLine = lines.indexOf(' option_end_index = i;'); // pre node 0.11.6 compat
|
||||
|
||||
if(endLine !== -1) { // check if it succedded or not.
|
||||
lines[endLine] = ' option_end_index = 1;';
|
||||
_log("patched node.cc")
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the new method of passing the args. Tested on node.js 0.12.5
|
||||
* and iojs 2.3.1
|
||||
**/
|
||||
if(endLine === -1) { // only if the pre-0.12.5 failed.
|
||||
var startLine = lines.indexOf(' while (index < nargs && argv[index][0] == \'-\') {'); // beginning of the function
|
||||
endLine = lines.indexOf(' // Copy remaining arguments.');
|
||||
endLine = endLine-1; // space, then it's at the }
|
||||
|
||||
// remove the offending lines
|
||||
if(startLine !== -1) {
|
||||
for (var i = startLine; i < endLine; i++) {
|
||||
lines[i] = undefined; // set the value to undefined so it's skipped by the join
|
||||
}
|
||||
_log('patched node.cc');
|
||||
}
|
||||
}
|
||||
|
||||
lines = lines.join('\n');
|
||||
next(null, lines);
|
||||
},
|
||||
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) {
|
||||
var files = glob.sync(dir + "/*");
|
||||
|
||||
for (var i = files.length; i--;) {
|
||||
var file = files[i];
|
||||
if (fs.statSync(file).isDirectory()) return file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the progress of a request object.
|
||||
*/
|
||||
|
||||
function _logProgress (req) {
|
||||
|
||||
req.on("response", function (resp) {
|
||||
|
||||
var len = parseInt(resp.headers["content-length"], 10),
|
||||
bar = new ProgressBar("[:bar]", {
|
||||
complete: "=",
|
||||
incomplete: " ",
|
||||
total: len,
|
||||
width: 100 // just use 100
|
||||
});
|
||||
|
||||
req.on("data", function (chunk) {
|
||||
bar.tick(chunk.length);
|
||||
});
|
||||
});
|
||||
|
||||
req.on("error", function(err) {
|
||||
console.log(err);
|
||||
_log("error", "failed to download node sources,");
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to parse the package.json for nexe information.
|
||||
*
|
||||
* @param {string} path - path to package.json
|
||||
* @param {object} options - fallback options
|
||||
*
|
||||
* @todo implement options overriding package defaults.
|
||||
* @todo make this much less hackily implemented....
|
||||
*
|
||||
* @return {object} nexe.compile options object
|
||||
**/
|
||||
exports.package = function(path, options) {
|
||||
var _package; // scope
|
||||
|
||||
// check if the file exists
|
||||
if(fs.existsSync(path)===false) {
|
||||
_log("warn", "no package.json found.");
|
||||
} else {
|
||||
_package = require(path);
|
||||
}
|
||||
|
||||
// replace ^$ w/ os specific extension on output
|
||||
if(isWin) {
|
||||
_package.nexe.output = _package.nexe.output.replace(/\^\$/, '.exe') // exe
|
||||
} else {
|
||||
_package.nexe.output = _package.nexe.output.replace(/\^\$/, '') // none
|
||||
}
|
||||
|
||||
// construct the object
|
||||
var obj = {
|
||||
input: (_package.nexe.input || options.i),
|
||||
output: (_package.nexe.output || options.o),
|
||||
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)
|
||||
}
|
||||
|
||||
Object.keys(_package.nexe).forEach(function(v,i) {
|
||||
if(v!=="runtime") {
|
||||
_log("log", v+" => '"+_package.nexe[v]+"'");
|
||||
}
|
||||
});
|
||||
Object.keys(_package.nexe.runtime).forEach(function(v,i) {
|
||||
_log("log", "runtime."+v+" => '"+_package.nexe.runtime[v]+"'");
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
+1
-3
@@ -1,3 +1 @@
|
||||
exports.compile = function(ops, callback) {
|
||||
|
||||
}
|
||||
module.exports = require("./exe");
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**/
|
||||
|
||||
var colors = require('colors');
|
||||
|
||||
/**
|
||||
* standard output, takes 3 different types.
|
||||
* log, error, and warn
|
||||
*
|
||||
* @param {any} arguments - Text to output.
|
||||
* @return undefined
|
||||
**/
|
||||
function _log () {
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 0),
|
||||
level = args.shift();
|
||||
|
||||
if (!~["log", "error", "warn"].indexOf(level)) {
|
||||
args.unshift(level);
|
||||
level = "log";
|
||||
}
|
||||
|
||||
if(level == "log") {
|
||||
args[0] = "----> " + args[0];
|
||||
} else if(level == "error") {
|
||||
args[0] = "....> " + colors.red("ERROR: ") + args[0]
|
||||
} else if(level == "warn") {
|
||||
args[0] = "....> " + colors.yellow("WARNING: ") + args[0]
|
||||
}
|
||||
|
||||
console[level].apply(console, args);
|
||||
}
|
||||
|
||||
// export the log function, for require()
|
||||
module.exports = _log;
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2013 Craig Condon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**/
|
||||
|
||||
var async = require("async"),
|
||||
fs = require("fs"),
|
||||
_log = require("./log");
|
||||
|
||||
/**
|
||||
* Monkey patch a file.
|
||||
*
|
||||
* @param {string} filePath - path to file.
|
||||
* @param {function} monkeyPatched - function to process contents
|
||||
* @param {function} processor - TODO: detail what this is
|
||||
* @param {function} complete - callback
|
||||
*
|
||||
* @return undefined
|
||||
*/
|
||||
function _monkeypatch (filePath, monkeyPatched, processor, complete) {
|
||||
|
||||
async.waterfall([
|
||||
|
||||
function read (next) {
|
||||
fs.readFile(filePath, "utf8", next);
|
||||
},
|
||||
|
||||
// TODO - need to parse gyp file - this is a bit hacker
|
||||
function monkeypatch (content, next) {
|
||||
|
||||
if (monkeyPatched(content)) return complete();
|
||||
|
||||
_log("monkey patch %s", filePath);
|
||||
processor(content, next);
|
||||
},
|
||||
|
||||
function write (content, next) {
|
||||
fs.writeFile(filePath, content, "utf8", next);
|
||||
}
|
||||
], complete);
|
||||
}
|
||||
|
||||
// export the function for require()
|
||||
module.exports = _monkeypatch;
|
||||
Generated
-2
@@ -1,2 +0,0 @@
|
||||
node_modules/
|
||||
node_modules/*
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
lib-cov/*
|
||||
*.swp
|
||||
*.swo
|
||||
node_modules
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
Copyright 2010 James Halliday (mail@substack.net)
|
||||
|
||||
This project is free software released under the MIT/X11 license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-474
@@ -1,474 +0,0 @@
|
||||
optimist
|
||||
========
|
||||
|
||||
Optimist is a node.js library for option parsing for people who hate option
|
||||
parsing. More specifically, this module is for people who like all the --bells
|
||||
and -whistlz of program usage but think optstrings are a waste of time.
|
||||
|
||||
With optimist, option parsing doesn't have to suck (as much).
|
||||
|
||||
examples
|
||||
========
|
||||
|
||||
With Optimist, the options are just a hash! No optstrings attached.
|
||||
-------------------------------------------------------------------
|
||||
|
||||
xup.js:
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist').argv;
|
||||
|
||||
if (argv.rif - 5 * argv.xup > 7.138) {
|
||||
console.log('Buy more riffiwobbles');
|
||||
}
|
||||
else {
|
||||
console.log('Sell the xupptumblers');
|
||||
}
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./xup.js --rif=55 --xup=9.52
|
||||
Buy more riffiwobbles
|
||||
|
||||
$ ./xup.js --rif 12 --xup 8.1
|
||||
Sell the xupptumblers
|
||||
|
||||

|
||||
|
||||
But wait! There's more! You can do short options:
|
||||
-------------------------------------------------
|
||||
|
||||
short.js:
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist').argv;
|
||||
console.log('(%d,%d)', argv.x, argv.y);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./short.js -x 10 -y 21
|
||||
(10,21)
|
||||
|
||||
And booleans, both long and short (and grouped):
|
||||
----------------------------------
|
||||
|
||||
bool.js:
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var util = require('util');
|
||||
var argv = require('optimist').argv;
|
||||
|
||||
if (argv.s) {
|
||||
util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: ');
|
||||
}
|
||||
console.log(
|
||||
(argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '')
|
||||
);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./bool.js -s
|
||||
The cat says: meow
|
||||
|
||||
$ ./bool.js -sp
|
||||
The cat says: meow.
|
||||
|
||||
$ ./bool.js -sp --fr
|
||||
Le chat dit: miaou.
|
||||
|
||||
And non-hypenated options too! Just use `argv._`!
|
||||
-------------------------------------------------
|
||||
|
||||
nonopt.js:
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist').argv;
|
||||
console.log('(%d,%d)', argv.x, argv.y);
|
||||
console.log(argv._);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./nonopt.js -x 6.82 -y 3.35 moo
|
||||
(6.82,3.35)
|
||||
[ 'moo' ]
|
||||
|
||||
$ ./nonopt.js foo -x 0.54 bar -y 1.12 baz
|
||||
(0.54,1.12)
|
||||
[ 'foo', 'bar', 'baz' ]
|
||||
|
||||
Plus, Optimist comes with .usage() and .demand()!
|
||||
-------------------------------------------------
|
||||
|
||||
divide.js:
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.usage('Usage: $0 -x [num] -y [num]')
|
||||
.demand(['x','y'])
|
||||
.argv;
|
||||
|
||||
console.log(argv.x / argv.y);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./divide.js -x 55 -y 11
|
||||
5
|
||||
|
||||
$ node ./divide.js -x 4.91 -z 2.51
|
||||
Usage: node ./divide.js -x [num] -y [num]
|
||||
|
||||
Options:
|
||||
-x [required]
|
||||
-y [required]
|
||||
|
||||
Missing required arguments: y
|
||||
|
||||
EVEN MORE HOLY COW
|
||||
------------------
|
||||
|
||||
default_singles.js:
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.default('x', 10)
|
||||
.default('y', 10)
|
||||
.argv
|
||||
;
|
||||
console.log(argv.x + argv.y);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./default_singles.js -x 5
|
||||
15
|
||||
|
||||
default_hash.js:
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.default({ x : 10, y : 10 })
|
||||
.argv
|
||||
;
|
||||
console.log(argv.x + argv.y);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./default_hash.js -y 7
|
||||
17
|
||||
|
||||
And if you really want to get all descriptive about it...
|
||||
---------------------------------------------------------
|
||||
|
||||
boolean_single.js
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.boolean('v')
|
||||
.argv
|
||||
;
|
||||
console.dir(argv);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./boolean_single.js -v foo bar baz
|
||||
true
|
||||
[ 'bar', 'baz', 'foo' ]
|
||||
|
||||
boolean_double.js
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.boolean(['x','y','z'])
|
||||
.argv
|
||||
;
|
||||
console.dir([ argv.x, argv.y, argv.z ]);
|
||||
console.dir(argv._);
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ ./boolean_double.js -x -z one two three
|
||||
[ true, false, true ]
|
||||
[ 'one', 'two', 'three' ]
|
||||
|
||||
Optimist is here to help...
|
||||
---------------------------
|
||||
|
||||
You can describe parameters for help messages and set aliases. Optimist figures
|
||||
out how to format a handy help string automatically.
|
||||
|
||||
line_count.js
|
||||
|
||||
````javascript
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.usage('Count the lines in a file.\nUsage: $0')
|
||||
.demand('f')
|
||||
.alias('f', 'file')
|
||||
.describe('f', 'Load a file')
|
||||
.argv
|
||||
;
|
||||
|
||||
var fs = require('fs');
|
||||
var s = fs.createReadStream(argv.file);
|
||||
|
||||
var lines = 0;
|
||||
s.on('data', function (buf) {
|
||||
lines += buf.toString().match(/\n/g).length;
|
||||
});
|
||||
|
||||
s.on('end', function () {
|
||||
console.log(lines);
|
||||
});
|
||||
````
|
||||
|
||||
***
|
||||
|
||||
$ node line_count.js
|
||||
Count the lines in a file.
|
||||
Usage: node ./line_count.js
|
||||
|
||||
Options:
|
||||
-f, --file Load a file [required]
|
||||
|
||||
Missing required arguments: f
|
||||
|
||||
$ node line_count.js --file line_count.js
|
||||
20
|
||||
|
||||
$ node line_count.js -f line_count.js
|
||||
20
|
||||
|
||||
methods
|
||||
=======
|
||||
|
||||
By itself,
|
||||
|
||||
````javascript
|
||||
require('optimist').argv
|
||||
`````
|
||||
|
||||
will use `process.argv` array to construct the `argv` object.
|
||||
|
||||
You can pass in the `process.argv` yourself:
|
||||
|
||||
````javascript
|
||||
require('optimist')([ '-x', '1', '-y', '2' ]).argv
|
||||
````
|
||||
|
||||
or use .parse() to do the same thing:
|
||||
|
||||
````javascript
|
||||
require('optimist').parse([ '-x', '1', '-y', '2' ])
|
||||
````
|
||||
|
||||
The rest of these methods below come in just before the terminating `.argv`.
|
||||
|
||||
.alias(key, alias)
|
||||
------------------
|
||||
|
||||
Set key names as equivalent such that updates to a key will propagate to aliases
|
||||
and vice-versa.
|
||||
|
||||
Optionally `.alias()` can take an object that maps keys to aliases.
|
||||
|
||||
.default(key, value)
|
||||
--------------------
|
||||
|
||||
Set `argv[key]` to `value` if no option was specified on `process.argv`.
|
||||
|
||||
Optionally `.default()` can take an object that maps keys to default values.
|
||||
|
||||
.demand(key)
|
||||
------------
|
||||
|
||||
If `key` is a string, show the usage information and exit if `key` wasn't
|
||||
specified in `process.argv`.
|
||||
|
||||
If `key` is a number, demand at least as many non-option arguments, which show
|
||||
up in `argv._`.
|
||||
|
||||
If `key` is an Array, demand each element.
|
||||
|
||||
.describe(key, desc)
|
||||
--------------------
|
||||
|
||||
Describe a `key` for the generated usage information.
|
||||
|
||||
Optionally `.describe()` can take an object that maps keys to descriptions.
|
||||
|
||||
.options(key, opt)
|
||||
------------------
|
||||
|
||||
Instead of chaining together `.alias().demand().default()`, you can specify
|
||||
keys in `opt` for each of the chainable methods.
|
||||
|
||||
For example:
|
||||
|
||||
````javascript
|
||||
var argv = require('optimist')
|
||||
.options('f', {
|
||||
alias : 'file',
|
||||
default : '/etc/passwd',
|
||||
})
|
||||
.argv
|
||||
;
|
||||
````
|
||||
|
||||
is the same as
|
||||
|
||||
````javascript
|
||||
var argv = require('optimist')
|
||||
.alias('f', 'file')
|
||||
.default('f', '/etc/passwd')
|
||||
.argv
|
||||
;
|
||||
````
|
||||
|
||||
Optionally `.options()` can take an object that maps keys to `opt` parameters.
|
||||
|
||||
.usage(message)
|
||||
---------------
|
||||
|
||||
Set a usage message to show which commands to use. Inside `message`, the string
|
||||
`$0` will get interpolated to the current script name or node command for the
|
||||
present script similar to how `$0` works in bash or perl.
|
||||
|
||||
.check(fn)
|
||||
----------
|
||||
|
||||
Check that certain conditions are met in the provided arguments.
|
||||
|
||||
If `fn` throws or returns `false`, show the thrown error, usage information, and
|
||||
exit.
|
||||
|
||||
.boolean(key)
|
||||
-------------
|
||||
|
||||
Interpret `key` as a boolean. If a non-flag option follows `key` in
|
||||
`process.argv`, that string won't get set as the value of `key`.
|
||||
|
||||
If `key` never shows up as a flag in `process.arguments`, `argv[key]` will be
|
||||
`false`.
|
||||
|
||||
If `key` is an Array, interpret all the elements as booleans.
|
||||
|
||||
.string(key)
|
||||
------------
|
||||
|
||||
Tell the parser logic not to interpret `key` as a number or boolean.
|
||||
This can be useful if you need to preserve leading zeros in an input.
|
||||
|
||||
If `key` is an Array, interpret all the elements as strings.
|
||||
|
||||
.wrap(columns)
|
||||
--------------
|
||||
|
||||
Format usage output to wrap at `columns` many columns.
|
||||
|
||||
.help()
|
||||
-------
|
||||
|
||||
Return the generated usage string.
|
||||
|
||||
.showHelp(fn=console.error)
|
||||
---------------------------
|
||||
|
||||
Print the usage data using `fn` for printing.
|
||||
|
||||
.parse(args)
|
||||
------------
|
||||
|
||||
Parse `args` instead of `process.argv`. Returns the `argv` object.
|
||||
|
||||
.argv
|
||||
-----
|
||||
|
||||
Get the arguments as a plain old object.
|
||||
|
||||
Arguments without a corresponding flag show up in the `argv._` array.
|
||||
|
||||
The script name or node command is available at `argv.$0` similarly to how `$0`
|
||||
works in bash or perl.
|
||||
|
||||
parsing tricks
|
||||
==============
|
||||
|
||||
stop parsing
|
||||
------------
|
||||
|
||||
Use `--` to stop parsing flags and stuff the remainder into `argv._`.
|
||||
|
||||
$ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4
|
||||
{ _: [ '-c', '3', '-d', '4' ],
|
||||
'$0': 'node ./examples/reflect.js',
|
||||
a: 1,
|
||||
b: 2 }
|
||||
|
||||
negate fields
|
||||
-------------
|
||||
|
||||
If you want to explicity set a field to false instead of just leaving it
|
||||
undefined or to override a default you can do `--no-key`.
|
||||
|
||||
$ node examples/reflect.js -a --no-b
|
||||
{ _: [],
|
||||
'$0': 'node ./examples/reflect.js',
|
||||
a: true,
|
||||
b: false }
|
||||
|
||||
numbers
|
||||
-------
|
||||
|
||||
Every argument that looks like a number (`!isNaN(Number(arg))`) is converted to
|
||||
one. This way you can just `net.createConnection(argv.port)` and you can add
|
||||
numbers out of `argv` with `+` without having that mean concatenation,
|
||||
which is super frustrating.
|
||||
|
||||
duplicates
|
||||
----------
|
||||
|
||||
If you specify a flag multiple times it will get turned into an array containing
|
||||
all the values in order.
|
||||
|
||||
$ node examples/reflect.js -x 5 -x 8 -x 0
|
||||
{ _: [],
|
||||
'$0': 'node ./examples/reflect.js',
|
||||
x: [ 5, 8, 0 ] }
|
||||
|
||||
installation
|
||||
============
|
||||
|
||||
With [npm](http://github.com/isaacs/npm), just do:
|
||||
npm install optimist
|
||||
|
||||
or clone this project on github:
|
||||
|
||||
git clone http://github.com/substack/node-optimist.git
|
||||
|
||||
To run the tests with [expresso](http://github.com/visionmedia/expresso),
|
||||
just do:
|
||||
|
||||
expresso
|
||||
|
||||
inspired By
|
||||
===========
|
||||
|
||||
This module is loosely inspired by Perl's
|
||||
[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm).
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var util = require('util');
|
||||
var argv = require('optimist').argv;
|
||||
|
||||
if (argv.s) {
|
||||
util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: ');
|
||||
}
|
||||
console.log(
|
||||
(argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '')
|
||||
);
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.boolean(['x','y','z'])
|
||||
.argv
|
||||
;
|
||||
console.dir([ argv.x, argv.y, argv.z ]);
|
||||
console.dir(argv._);
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.boolean('v')
|
||||
.argv
|
||||
;
|
||||
console.dir(argv.v);
|
||||
console.dir(argv._);
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var argv = require('optimist')
|
||||
.default({ x : 10, y : 10 })
|
||||
.argv
|
||||
;
|
||||
|
||||
console.log(argv.x + argv.y);
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.default('x', 10)
|
||||
.default('y', 10)
|
||||
.argv
|
||||
;
|
||||
console.log(argv.x + argv.y);
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var argv = require('optimist')
|
||||
.usage('Usage: $0 -x [num] -y [num]')
|
||||
.demand(['x','y'])
|
||||
.argv;
|
||||
|
||||
console.log(argv.x / argv.y);
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.usage('Count the lines in a file.\nUsage: $0')
|
||||
.demand('f')
|
||||
.alias('f', 'file')
|
||||
.describe('f', 'Load a file')
|
||||
.argv
|
||||
;
|
||||
|
||||
var fs = require('fs');
|
||||
var s = fs.createReadStream(argv.file);
|
||||
|
||||
var lines = 0;
|
||||
s.on('data', function (buf) {
|
||||
lines += buf.toString().match(/\n/g).length;
|
||||
});
|
||||
|
||||
s.on('end', function () {
|
||||
console.log(lines);
|
||||
});
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.usage('Count the lines in a file.\nUsage: $0')
|
||||
.options({
|
||||
file : {
|
||||
demand : true,
|
||||
alias : 'f',
|
||||
description : 'Load a file'
|
||||
},
|
||||
base : {
|
||||
alias : 'b',
|
||||
description : 'Numeric base to use for output',
|
||||
default : 10,
|
||||
},
|
||||
})
|
||||
.argv
|
||||
;
|
||||
|
||||
var fs = require('fs');
|
||||
var s = fs.createReadStream(argv.file);
|
||||
|
||||
var lines = 0;
|
||||
s.on('data', function (buf) {
|
||||
lines += buf.toString().match(/\n/g).length;
|
||||
});
|
||||
|
||||
s.on('end', function () {
|
||||
console.log(lines.toString(argv.base));
|
||||
});
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.usage('Count the lines in a file.\nUsage: $0')
|
||||
.wrap(80)
|
||||
.demand('f')
|
||||
.alias('f', [ 'file', 'filename' ])
|
||||
.describe('f',
|
||||
"Load a file. It's pretty important."
|
||||
+ " Required even. So you'd better specify it."
|
||||
)
|
||||
.alias('b', 'base')
|
||||
.describe('b', 'Numeric base to display the number of lines in')
|
||||
.default('b', 10)
|
||||
.describe('x', 'Super-secret optional parameter which is secret')
|
||||
.default('x', '')
|
||||
.argv
|
||||
;
|
||||
|
||||
var fs = require('fs');
|
||||
var s = fs.createReadStream(argv.file);
|
||||
|
||||
var lines = 0;
|
||||
s.on('data', function (buf) {
|
||||
lines += buf.toString().match(/\n/g).length;
|
||||
});
|
||||
|
||||
s.on('end', function () {
|
||||
console.log(lines.toString(argv.base));
|
||||
});
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist').argv;
|
||||
console.log('(%d,%d)', argv.x, argv.y);
|
||||
console.log(argv._);
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
console.dir(require('optimist').argv);
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist').argv;
|
||||
console.log('(%d,%d)', argv.x, argv.y);
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist')
|
||||
.string('x', 'y')
|
||||
.argv
|
||||
;
|
||||
console.dir([ argv.x, argv.y ]);
|
||||
|
||||
/* Turns off numeric coercion:
|
||||
./node string.js -x 000123 -y 9876
|
||||
[ '000123', '9876' ]
|
||||
*/
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
var optimist = require('./../index');
|
||||
|
||||
var argv = optimist.usage('This is my awesome program', {
|
||||
'about': {
|
||||
description: 'Provide some details about the author of this program',
|
||||
required: true,
|
||||
short: 'a',
|
||||
},
|
||||
'info': {
|
||||
description: 'Provide some information about the node.js agains!!!!!!',
|
||||
boolean: true,
|
||||
short: 'i'
|
||||
}
|
||||
}).argv;
|
||||
|
||||
optimist.showHelp();
|
||||
|
||||
console.log('\n\nInspecting options');
|
||||
console.dir(argv);
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('optimist').argv;
|
||||
|
||||
if (argv.rif - 5 * argv.xup > 7.138) {
|
||||
console.log('Buy more riffiwobbles');
|
||||
}
|
||||
else {
|
||||
console.log('Sell the xupptumblers');
|
||||
}
|
||||
|
||||
-457
@@ -1,457 +0,0 @@
|
||||
var path = require('path');
|
||||
var wordwrap = require('wordwrap');
|
||||
|
||||
/* Hack an instance of Argv with process.argv into Argv
|
||||
so people can do
|
||||
require('optimist')(['--beeble=1','-z','zizzle']).argv
|
||||
to parse a list of args and
|
||||
require('optimist').argv
|
||||
to get a parsed version of process.argv.
|
||||
*/
|
||||
|
||||
var inst = Argv(process.argv.slice(2));
|
||||
Object.keys(inst).forEach(function (key) {
|
||||
Argv[key] = typeof inst[key] == 'function'
|
||||
? inst[key].bind(inst)
|
||||
: inst[key];
|
||||
});
|
||||
|
||||
var exports = module.exports = Argv;
|
||||
function Argv (args, cwd) {
|
||||
var self = {};
|
||||
if (!cwd) cwd = process.cwd();
|
||||
|
||||
self.$0 = process.argv
|
||||
.slice(0,2)
|
||||
.map(function (x) {
|
||||
var b = rebase(cwd, x);
|
||||
return x.match(/^\//) && b.length < x.length
|
||||
? b : x
|
||||
})
|
||||
.join(' ')
|
||||
;
|
||||
|
||||
if (process.argv[1] == process.env._) {
|
||||
self.$0 = process.env._.replace(
|
||||
path.dirname(process.execPath) + '/', ''
|
||||
);
|
||||
}
|
||||
|
||||
var flags = { bools : {}, strings : {} };
|
||||
|
||||
self.boolean = function (bools) {
|
||||
if (!Array.isArray(bools)) {
|
||||
bools = [].slice.call(arguments);
|
||||
}
|
||||
|
||||
bools.forEach(function (name) {
|
||||
flags.bools[name] = true;
|
||||
});
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
self.string = function (strings) {
|
||||
if (!Array.isArray(strings)) {
|
||||
strings = [].slice.call(arguments);
|
||||
}
|
||||
|
||||
strings.forEach(function (name) {
|
||||
flags.strings[name] = true;
|
||||
});
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
var aliases = {};
|
||||
self.alias = function (x, y) {
|
||||
if (typeof x === 'object') {
|
||||
Object.keys(x).forEach(function (key) {
|
||||
self.alias(key, x[key]);
|
||||
});
|
||||
}
|
||||
else if (Array.isArray(y)) {
|
||||
y.forEach(function (yy) {
|
||||
self.alias(x, yy);
|
||||
});
|
||||
}
|
||||
else {
|
||||
var zs = (aliases[x] || []).concat(aliases[y] || []).concat(x, y);
|
||||
aliases[x] = zs.filter(function (z) { return z != x });
|
||||
aliases[y] = zs.filter(function (z) { return z != y });
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
var demanded = {};
|
||||
self.demand = function (keys) {
|
||||
if (typeof keys == 'number') {
|
||||
if (!demanded._) demanded._ = 0;
|
||||
demanded._ += keys;
|
||||
}
|
||||
else if (Array.isArray(keys)) {
|
||||
keys.forEach(function (key) {
|
||||
self.demand(key);
|
||||
});
|
||||
}
|
||||
else {
|
||||
demanded[keys] = true;
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
var usage;
|
||||
self.usage = function (msg, opts) {
|
||||
if (!opts && typeof msg === 'object') {
|
||||
opts = msg;
|
||||
msg = null;
|
||||
}
|
||||
|
||||
usage = msg;
|
||||
|
||||
if (opts) self.options(opts);
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
function fail (msg) {
|
||||
self.showHelp();
|
||||
if (msg) console.error(msg);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var checks = [];
|
||||
self.check = function (f) {
|
||||
checks.push(f);
|
||||
return self;
|
||||
};
|
||||
|
||||
var defaults = {};
|
||||
self.default = function (key, value) {
|
||||
if (typeof key === 'object') {
|
||||
Object.keys(key).forEach(function (k) {
|
||||
self.default(k, key[k]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
defaults[key] = value;
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
var descriptions = {};
|
||||
self.describe = function (key, desc) {
|
||||
if (typeof key === 'object') {
|
||||
Object.keys(key).forEach(function (k) {
|
||||
self.describe(k, key[k]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
descriptions[key] = desc;
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
self.parse = function (args) {
|
||||
return Argv(args).argv;
|
||||
};
|
||||
|
||||
self.option = self.options = function (key, opt) {
|
||||
if (typeof key === 'object') {
|
||||
Object.keys(key).forEach(function (k) {
|
||||
self.options(k, key[k]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (opt.alias) self.alias(key, opt.alias);
|
||||
if (opt.demand) self.demand(key);
|
||||
if (opt.default) self.default(key, opt.default);
|
||||
|
||||
if (opt.boolean || opt.type === 'boolean') {
|
||||
self.boolean(key);
|
||||
}
|
||||
if (opt.string || opt.type === 'string') {
|
||||
self.string(key);
|
||||
}
|
||||
|
||||
var desc = opt.describe || opt.description || opt.desc;
|
||||
if (desc) {
|
||||
self.describe(key, desc);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
var wrap = null;
|
||||
self.wrap = function (cols) {
|
||||
wrap = cols;
|
||||
return self;
|
||||
};
|
||||
|
||||
self.showHelp = function (fn) {
|
||||
if (!fn) fn = console.error;
|
||||
fn(self.help());
|
||||
};
|
||||
|
||||
self.help = function () {
|
||||
var keys = Object.keys(
|
||||
Object.keys(descriptions)
|
||||
.concat(Object.keys(demanded))
|
||||
.concat(Object.keys(defaults))
|
||||
.reduce(function (acc, key) {
|
||||
if (key !== '_') acc[key] = true;
|
||||
return acc;
|
||||
}, {})
|
||||
);
|
||||
|
||||
var help = keys.length ? [ 'Options:' ] : [];
|
||||
|
||||
if (usage) {
|
||||
help.unshift(usage.replace(/\$0/g, self.$0), '');
|
||||
}
|
||||
|
||||
var switches = keys.reduce(function (acc, key) {
|
||||
acc[key] = [ key ].concat(aliases[key] || [])
|
||||
.map(function (sw) {
|
||||
return (sw.length > 1 ? '--' : '-') + sw
|
||||
})
|
||||
.join(', ')
|
||||
;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
var switchlen = longest(Object.keys(switches).map(function (s) {
|
||||
return switches[s] || '';
|
||||
}));
|
||||
|
||||
var desclen = longest(Object.keys(descriptions).map(function (d) {
|
||||
return descriptions[d] || '';
|
||||
}));
|
||||
|
||||
keys.forEach(function (key) {
|
||||
var kswitch = switches[key];
|
||||
var desc = descriptions[key] || '';
|
||||
|
||||
if (wrap) {
|
||||
desc = wordwrap(switchlen + 4, wrap)(desc)
|
||||
.slice(switchlen + 4)
|
||||
;
|
||||
}
|
||||
|
||||
var spadding = new Array(
|
||||
Math.max(switchlen - kswitch.length + 3, 0)
|
||||
).join(' ');
|
||||
|
||||
var dpadding = new Array(
|
||||
Math.max(desclen - desc.length + 1, 0)
|
||||
).join(' ');
|
||||
|
||||
var type = null;
|
||||
|
||||
if (flags.bools[key]) type = '[boolean]';
|
||||
if (flags.strings[key]) type = '[string]';
|
||||
|
||||
if (!wrap && dpadding.length > 0) {
|
||||
desc += dpadding;
|
||||
}
|
||||
|
||||
var prelude = ' ' + kswitch + spadding;
|
||||
var extra = [
|
||||
type,
|
||||
demanded[key]
|
||||
? '[required]'
|
||||
: null
|
||||
,
|
||||
defaults[key] !== undefined
|
||||
? '[default: ' + JSON.stringify(defaults[key]) + ']'
|
||||
: null
|
||||
,
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
var body = [ desc, extra ].filter(Boolean).join(' ');
|
||||
|
||||
if (wrap) {
|
||||
var dlines = desc.split('\n');
|
||||
var dlen = dlines.slice(-1)[0].length
|
||||
+ (dlines.length === 1 ? prelude.length : 0)
|
||||
|
||||
body = desc + (dlen + extra.length > wrap - 2
|
||||
? '\n'
|
||||
+ new Array(wrap - extra.length + 1).join(' ')
|
||||
+ extra
|
||||
: new Array(wrap - extra.length - dlen + 1).join(' ')
|
||||
+ extra
|
||||
);
|
||||
}
|
||||
|
||||
help.push(prelude + body);
|
||||
});
|
||||
|
||||
help.push('');
|
||||
return help.join('\n');
|
||||
};
|
||||
|
||||
Object.defineProperty(self, 'argv', {
|
||||
get : parseArgs,
|
||||
enumerable : true,
|
||||
});
|
||||
|
||||
function parseArgs () {
|
||||
var argv = { _ : [], $0 : self.$0 };
|
||||
Object.keys(flags.bools).forEach(function (key) {
|
||||
setArg(key, defaults[key] || false);
|
||||
});
|
||||
|
||||
function setArg (key, val) {
|
||||
var num = Number(val);
|
||||
var value = typeof val !== 'string' || isNaN(num) ? val : num;
|
||||
if (flags.strings[key]) value = val;
|
||||
|
||||
if (key in argv && !flags.bools[key]) {
|
||||
if (!Array.isArray(argv[key])) {
|
||||
argv[key] = [ argv[key] ];
|
||||
}
|
||||
argv[key].push(value);
|
||||
}
|
||||
else {
|
||||
argv[key] = value;
|
||||
}
|
||||
|
||||
(aliases[key] || []).forEach(function (x) {
|
||||
argv[x] = argv[key];
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
|
||||
if (arg === '--') {
|
||||
argv._.push.apply(argv._, args.slice(i + 1));
|
||||
break;
|
||||
}
|
||||
else if (arg.match(/^--.+=/)) {
|
||||
var m = arg.match(/^--([^=]+)=(.*)/);
|
||||
setArg(m[1], m[2]);
|
||||
}
|
||||
else if (arg.match(/^--no-.+/)) {
|
||||
var key = arg.match(/^--no-(.+)/)[1];
|
||||
setArg(key, false);
|
||||
}
|
||||
else if (arg.match(/^--.+/)) {
|
||||
var key = arg.match(/^--(.+)/)[1];
|
||||
var next = args[i + 1];
|
||||
if (next !== undefined && !next.match(/^-/)
|
||||
&& !flags.bools[key]) {
|
||||
setArg(key, next);
|
||||
i++;
|
||||
}
|
||||
else if (flags.bools[key] && /true|false/.test(next)) {
|
||||
setArg(key, next === 'true');
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
setArg(key, true);
|
||||
}
|
||||
}
|
||||
else if (arg.match(/^-[^-]+/)) {
|
||||
var letters = arg.slice(1,-1).split('');
|
||||
|
||||
var broken = false;
|
||||
for (var j = 0; j < letters.length; j++) {
|
||||
if (letters[j+1] && letters[j+1].match(/\W/)) {
|
||||
setArg(letters[j], arg.slice(j+2));
|
||||
broken = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
setArg(letters[j], true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!broken) {
|
||||
var key = arg.slice(-1)[0];
|
||||
|
||||
if (args[i+1] && !args[i+1].match(/^-/)
|
||||
&& !flags.bools[key]) {
|
||||
setArg(key, args[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (args[i+1] && flags.bools[key] && /true|false/.test(args[i+1])) {
|
||||
setArg(key, args[i+1] === 'true');
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
setArg(key, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var n = Number(arg);
|
||||
argv._.push(flags.strings['_'] || isNaN(n) ? arg : n);
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(defaults).forEach(function (key) {
|
||||
if (!(key in argv)) {
|
||||
argv[key] = defaults[key];
|
||||
}
|
||||
});
|
||||
|
||||
if (demanded._ && argv._.length < demanded._) {
|
||||
fail('Not enough non-option arguments: got '
|
||||
+ argv._.length + ', need at least ' + demanded._
|
||||
);
|
||||
}
|
||||
|
||||
var missing = [];
|
||||
Object.keys(demanded).forEach(function (key) {
|
||||
if (!argv[key]) missing.push(key);
|
||||
});
|
||||
|
||||
if (missing.length) {
|
||||
fail('Missing required arguments: ' + missing.join(', '));
|
||||
}
|
||||
|
||||
checks.forEach(function (f) {
|
||||
try {
|
||||
if (f(argv) === false) {
|
||||
fail('Argument check failed: ' + f.toString());
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
fail(err)
|
||||
}
|
||||
});
|
||||
|
||||
return argv;
|
||||
}
|
||||
|
||||
function longest (xs) {
|
||||
return Math.max.apply(
|
||||
null,
|
||||
xs.map(function (x) { return x.length })
|
||||
);
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
// rebase an absolute path to a relative one with respect to a base directory
|
||||
// exported for tests
|
||||
exports.rebase = rebase;
|
||||
function rebase (base, dir) {
|
||||
var ds = path.normalize(dir).split('/').slice(1);
|
||||
var bs = path.normalize(base).split('/').slice(1);
|
||||
|
||||
for (var i = 0; ds[i] && ds[i] == bs[i]; i++);
|
||||
ds.splice(0, i); bs.splice(0, i);
|
||||
|
||||
var p = path.normalize(
|
||||
bs.map(function () { return '..' }).concat(ds).join('/')
|
||||
).replace(/\/$/,'').replace(/^$/, '.');
|
||||
return p.match(/^[.\/]/) ? p : './' + p;
|
||||
};
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"name" : "optimist",
|
||||
"version" : "0.2.8",
|
||||
"description" : "Light-weight option parsing with an argv hash. No optstrings attached.",
|
||||
"main" : "./index.js",
|
||||
"directories" : {
|
||||
"lib" : ".",
|
||||
"test" : "test",
|
||||
"example" : "examples"
|
||||
},
|
||||
"dependencies" : {
|
||||
"wordwrap" : ">=0.0.1 <0.1.0"
|
||||
},
|
||||
"devDependencies" : {
|
||||
"hashish": "0.0.x",
|
||||
"expresso" : "0.7.x"
|
||||
},
|
||||
"scripts" : {
|
||||
"test" : "expresso"
|
||||
},
|
||||
"repository" : {
|
||||
"type" : "git",
|
||||
"url" : "http://github.com/substack/node-optimist.git"
|
||||
},
|
||||
"keywords" : [
|
||||
"argument",
|
||||
"args",
|
||||
"option",
|
||||
"parser",
|
||||
"parsing",
|
||||
"cli",
|
||||
"command"
|
||||
],
|
||||
"author" : {
|
||||
"name" : "James Halliday",
|
||||
"email" : "mail@substack.net",
|
||||
"url" : "http://substack.net"
|
||||
},
|
||||
"license" : "MIT/X11",
|
||||
"engine" : {
|
||||
"node" : ">=0.4"
|
||||
}
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
var spawn = require('child_process').spawn;
|
||||
var assert = require('assert');
|
||||
|
||||
exports.dotSlashEmpty = function () {
|
||||
testCmd('./bin.js', []);
|
||||
};
|
||||
|
||||
exports.dotSlashArgs = function () {
|
||||
testCmd('./bin.js', [ 'a', 'b', 'c' ]);
|
||||
};
|
||||
|
||||
exports.nodeEmpty = function () {
|
||||
testCmd('node bin.js', []);
|
||||
};
|
||||
|
||||
exports.nodeArgs = function () {
|
||||
testCmd('node bin.js', [ 'x', 'y', 'z' ]);
|
||||
};
|
||||
|
||||
exports.whichNodeEmpty = function () {
|
||||
var which = spawn('which', ['node']);
|
||||
|
||||
which.stdout.on('data', function (buf) {
|
||||
testCmd(buf.toString().trim() + ' bin.js', []);
|
||||
});
|
||||
|
||||
which.stderr.on('data', function (err) {
|
||||
assert.fail(err.toString());
|
||||
});
|
||||
};
|
||||
|
||||
exports.whichNodeArgs = function () {
|
||||
var which = spawn('which', ['node']);
|
||||
|
||||
which.stdout.on('data', function (buf) {
|
||||
testCmd(buf.toString().trim() + ' bin.js', [ 'q', 'r' ]);
|
||||
});
|
||||
|
||||
which.stderr.on('data', function (err) {
|
||||
assert.fail(err.toString());
|
||||
});
|
||||
};
|
||||
|
||||
function testCmd (cmd, args) {
|
||||
var to = setTimeout(function () {
|
||||
assert.fail('Never got stdout data.')
|
||||
}, 5000);
|
||||
|
||||
var oldDir = process.cwd();
|
||||
process.chdir(__dirname + '/_');
|
||||
|
||||
var cmds = cmd.split(' ');
|
||||
|
||||
var bin = spawn(cmds[0], cmds.slice(1).concat(args.map(String)));
|
||||
process.chdir(oldDir);
|
||||
|
||||
bin.stderr.on('data', function (err) {
|
||||
assert.fail(err.toString());
|
||||
});
|
||||
|
||||
bin.stdout.on('data', function (buf) {
|
||||
clearTimeout(to);
|
||||
var _ = JSON.parse(buf.toString());
|
||||
assert.eql(_.map(String), args.map(String));
|
||||
});
|
||||
}
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
console.log(JSON.stringify(process.argv));
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
var argv = require('../../index').argv
|
||||
console.log(JSON.stringify(argv._));
|
||||
-304
@@ -1,304 +0,0 @@
|
||||
var optimist = require('../index');
|
||||
var assert = require('assert');
|
||||
var path = require('path');
|
||||
|
||||
var localExpresso = path.normalize(
|
||||
__dirname + '/../node_modules/.bin/expresso'
|
||||
);
|
||||
|
||||
var expresso = process.argv[1] === localExpresso
|
||||
? 'node ./node_modules/.bin/expresso'
|
||||
: 'expresso'
|
||||
;
|
||||
|
||||
exports['short boolean'] = function () {
|
||||
var parse = optimist.parse([ '-b' ]);
|
||||
assert.eql(parse, { b : true, _ : [], $0 : expresso });
|
||||
assert.eql(typeof parse.b, 'boolean');
|
||||
};
|
||||
|
||||
exports['long boolean'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '--bool' ]),
|
||||
{ bool : true, _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports.bare = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ 'foo', 'bar', 'baz' ]),
|
||||
{ _ : [ 'foo', 'bar', 'baz' ], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['short group'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-cats' ]),
|
||||
{ c : true, a : true, t : true, s : true, _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['short group next'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-cats', 'meow' ]),
|
||||
{ c : true, a : true, t : true, s : 'meow', _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['short capture'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-h', 'localhost' ]),
|
||||
{ h : 'localhost', _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['short captures'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-h', 'localhost', '-p', '555' ]),
|
||||
{ h : 'localhost', p : 555, _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['long capture sp'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '--pow', 'xixxle' ]),
|
||||
{ pow : 'xixxle', _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['long capture eq'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '--pow=xixxle' ]),
|
||||
{ pow : 'xixxle', _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['long captures sp'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '--host', 'localhost', '--port', '555' ]),
|
||||
{ host : 'localhost', port : 555, _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['long captures eq'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '--host=localhost', '--port=555' ]),
|
||||
{ host : 'localhost', port : 555, _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports['mixed short bool and capture'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
|
||||
{
|
||||
f : true, p : 555, h : 'localhost',
|
||||
_ : [ 'script.js' ], $0 : expresso,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports['short and long'] = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
|
||||
{
|
||||
f : true, p : 555, h : 'localhost',
|
||||
_ : [ 'script.js' ], $0 : expresso,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.no = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '--no-moo' ]),
|
||||
{ moo : false, _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports.multi = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]),
|
||||
{ v : ['a','b','c'], _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports.comprehensive = function () {
|
||||
assert.eql(
|
||||
optimist.parse([
|
||||
'--name=meowmers', 'bare', '-cats', 'woo',
|
||||
'-h', 'awesome', '--multi=quux',
|
||||
'--key', 'value',
|
||||
'-b', '--bool', '--no-meep', '--multi=baz',
|
||||
'--', '--not-a-flag', 'eek'
|
||||
]),
|
||||
{
|
||||
c : true,
|
||||
a : true,
|
||||
t : true,
|
||||
s : 'woo',
|
||||
h : 'awesome',
|
||||
b : true,
|
||||
bool : true,
|
||||
key : 'value',
|
||||
multi : [ 'quux', 'baz' ],
|
||||
meep : false,
|
||||
name : 'meowmers',
|
||||
_ : [ 'bare', '--not-a-flag', 'eek' ],
|
||||
$0 : expresso
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.nums = function () {
|
||||
var argv = optimist.parse([
|
||||
'-x', '1234',
|
||||
'-y', '5.67',
|
||||
'-z', '1e7',
|
||||
'-w', '10f',
|
||||
'--hex', '0xdeadbeef',
|
||||
'789',
|
||||
]);
|
||||
assert.eql(argv, {
|
||||
x : 1234,
|
||||
y : 5.67,
|
||||
z : 1e7,
|
||||
w : '10f',
|
||||
hex : 0xdeadbeef,
|
||||
_ : [ 789 ],
|
||||
$0 : expresso
|
||||
});
|
||||
assert.eql(typeof argv.x, 'number');
|
||||
assert.eql(typeof argv.y, 'number');
|
||||
assert.eql(typeof argv.z, 'number');
|
||||
assert.eql(typeof argv.w, 'string');
|
||||
assert.eql(typeof argv.hex, 'number');
|
||||
assert.eql(typeof argv._[0], 'number');
|
||||
};
|
||||
|
||||
exports['flag boolean'] = function () {
|
||||
var parse = optimist([ '-t', 'moo' ]).boolean(['t']).argv;
|
||||
assert.eql(parse, { t : true, _ : [ 'moo' ], $0 : expresso });
|
||||
assert.eql(typeof parse.t, 'boolean');
|
||||
};
|
||||
|
||||
exports['flag boolean value'] = function () {
|
||||
var parse = optimist(['--verbose', 'false', 'moo', '-t', 'true'])
|
||||
.boolean(['t', 'verbose']).default('verbose', true).argv;
|
||||
|
||||
assert.eql(parse, {
|
||||
verbose: false,
|
||||
t: true,
|
||||
_: ['moo'],
|
||||
$0 : expresso
|
||||
});
|
||||
|
||||
assert.eql(typeof parse.verbose, 'boolean');
|
||||
assert.eql(typeof parse.t, 'boolean');
|
||||
};
|
||||
|
||||
exports['flag boolean default false'] = function () {
|
||||
var parse = optimist(['moo'])
|
||||
.boolean(['t', 'verbose'])
|
||||
.default('verbose', false)
|
||||
.default('t', false).argv;
|
||||
|
||||
assert.eql(parse, {
|
||||
verbose: false,
|
||||
t: false,
|
||||
_: ['moo'],
|
||||
$0 : expresso
|
||||
});
|
||||
|
||||
assert.eql(typeof parse.verbose, 'boolean');
|
||||
assert.eql(typeof parse.t, 'boolean');
|
||||
|
||||
};
|
||||
|
||||
exports['boolean groups'] = function () {
|
||||
var parse = optimist([ '-x', '-z', 'one', 'two', 'three' ])
|
||||
.boolean(['x','y','z']).argv;
|
||||
|
||||
assert.eql(parse, {
|
||||
x : true,
|
||||
y : false,
|
||||
z : true,
|
||||
_ : [ 'one', 'two', 'three' ],
|
||||
$0 : expresso
|
||||
});
|
||||
|
||||
assert.eql(typeof parse.x, 'boolean');
|
||||
assert.eql(typeof parse.y, 'boolean');
|
||||
assert.eql(typeof parse.z, 'boolean');
|
||||
};
|
||||
|
||||
exports.strings = function () {
|
||||
var s = optimist([ '-s', '0001234' ]).string('s').argv.s;
|
||||
assert.eql(s, '0001234');
|
||||
assert.eql(typeof s, 'string');
|
||||
|
||||
var x = optimist([ '-x', '56' ]).string('x').argv.x;
|
||||
assert.eql(x, '56');
|
||||
assert.eql(typeof x, 'string');
|
||||
};
|
||||
|
||||
exports.stringArgs = function () {
|
||||
var s = optimist([ ' ', ' ' ]).string('_').argv._;
|
||||
assert.eql(s.length, 2);
|
||||
assert.eql(typeof s[0], 'string');
|
||||
assert.eql(s[0], ' ');
|
||||
assert.eql(typeof s[1], 'string');
|
||||
assert.eql(s[1], ' ');
|
||||
};
|
||||
|
||||
exports.slashBreak = function () {
|
||||
assert.eql(
|
||||
optimist.parse([ '-I/foo/bar/baz' ]),
|
||||
{ I : '/foo/bar/baz', _ : [], $0 : expresso }
|
||||
);
|
||||
assert.eql(
|
||||
optimist.parse([ '-xyz/foo/bar/baz' ]),
|
||||
{ x : true, y : true, z : '/foo/bar/baz', _ : [], $0 : expresso }
|
||||
);
|
||||
};
|
||||
|
||||
exports.alias = function () {
|
||||
var argv = optimist([ '-f', '11', '--zoom', '55' ])
|
||||
.alias('z', 'zoom')
|
||||
.argv
|
||||
;
|
||||
assert.equal(argv.zoom, 55);
|
||||
assert.equal(argv.z, argv.zoom);
|
||||
assert.equal(argv.f, 11);
|
||||
};
|
||||
|
||||
exports.multiAlias = function () {
|
||||
var argv = optimist([ '-f', '11', '--zoom', '55' ])
|
||||
.alias('z', [ 'zm', 'zoom' ])
|
||||
.argv
|
||||
;
|
||||
assert.equal(argv.zoom, 55);
|
||||
assert.equal(argv.z, argv.zoom);
|
||||
assert.equal(argv.z, argv.zm);
|
||||
assert.equal(argv.f, 11);
|
||||
};
|
||||
|
||||
exports['boolean default true'] = function () {
|
||||
var argv = optimist.options({
|
||||
sometrue: {
|
||||
boolean: true,
|
||||
default: true
|
||||
}
|
||||
}).argv;
|
||||
|
||||
assert.equal(argv.sometrue, true);
|
||||
};
|
||||
|
||||
exports['boolean default false'] = function () {
|
||||
var argv = optimist.options({
|
||||
somefalse: {
|
||||
boolean: true,
|
||||
default: false
|
||||
}
|
||||
}).argv;
|
||||
|
||||
assert.equal(argv.somefalse, false);
|
||||
};
|
||||
-256
@@ -1,256 +0,0 @@
|
||||
var Hash = require('hashish');
|
||||
var optimist = require('../index');
|
||||
var assert = require('assert');
|
||||
|
||||
exports.usageFail = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('-x 10 -z 20'.split(' '))
|
||||
.usage('Usage: $0 -x NUM -y NUM')
|
||||
.demand(['x','y'])
|
||||
.argv;
|
||||
});
|
||||
assert.deepEqual(
|
||||
r.result,
|
||||
{ x : 10, z : 20, _ : [], $0 : './usage' }
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
r.errors.join('\n').split(/\n+/),
|
||||
[
|
||||
'Usage: ./usage -x NUM -y NUM',
|
||||
'Options:',
|
||||
' -x [required]',
|
||||
' -y [required]',
|
||||
'Missing required arguments: y',
|
||||
]
|
||||
);
|
||||
assert.deepEqual(r.logs, []);
|
||||
assert.ok(r.exit);
|
||||
};
|
||||
|
||||
exports.usagePass = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('-x 10 -y 20'.split(' '))
|
||||
.usage('Usage: $0 -x NUM -y NUM')
|
||||
.demand(['x','y'])
|
||||
.argv;
|
||||
});
|
||||
assert.deepEqual(r, {
|
||||
result : { x : 10, y : 20, _ : [], $0 : './usage' },
|
||||
errors : [],
|
||||
logs : [],
|
||||
exit : false,
|
||||
});
|
||||
};
|
||||
|
||||
exports.checkPass = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('-x 10 -y 20'.split(' '))
|
||||
.usage('Usage: $0 -x NUM -y NUM')
|
||||
.check(function (argv) {
|
||||
if (!('x' in argv)) throw 'You forgot about -x';
|
||||
if (!('y' in argv)) throw 'You forgot about -y';
|
||||
})
|
||||
.argv;
|
||||
});
|
||||
assert.deepEqual(r, {
|
||||
result : { x : 10, y : 20, _ : [], $0 : './usage' },
|
||||
errors : [],
|
||||
logs : [],
|
||||
exit : false,
|
||||
});
|
||||
};
|
||||
|
||||
exports.checkFail = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('-x 10 -z 20'.split(' '))
|
||||
.usage('Usage: $0 -x NUM -y NUM')
|
||||
.check(function (argv) {
|
||||
if (!('x' in argv)) throw 'You forgot about -x';
|
||||
if (!('y' in argv)) throw 'You forgot about -y';
|
||||
})
|
||||
.argv;
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
r.result,
|
||||
{ x : 10, z : 20, _ : [], $0 : './usage' }
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
r.errors.join('\n').split(/\n+/),
|
||||
[
|
||||
'Usage: ./usage -x NUM -y NUM',
|
||||
'You forgot about -y'
|
||||
]
|
||||
);
|
||||
|
||||
assert.deepEqual(r.logs, []);
|
||||
assert.ok(r.exit);
|
||||
};
|
||||
|
||||
exports.checkCondPass = function () {
|
||||
function checker (argv) {
|
||||
return 'x' in argv && 'y' in argv;
|
||||
}
|
||||
|
||||
var r = checkUsage(function () {
|
||||
return optimist('-x 10 -y 20'.split(' '))
|
||||
.usage('Usage: $0 -x NUM -y NUM')
|
||||
.check(checker)
|
||||
.argv;
|
||||
});
|
||||
assert.deepEqual(r, {
|
||||
result : { x : 10, y : 20, _ : [], $0 : './usage' },
|
||||
errors : [],
|
||||
logs : [],
|
||||
exit : false,
|
||||
});
|
||||
};
|
||||
|
||||
exports.checkCondFail = function () {
|
||||
function checker (argv) {
|
||||
return 'x' in argv && 'y' in argv;
|
||||
}
|
||||
|
||||
var r = checkUsage(function () {
|
||||
return optimist('-x 10 -z 20'.split(' '))
|
||||
.usage('Usage: $0 -x NUM -y NUM')
|
||||
.check(checker)
|
||||
.argv;
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
r.result,
|
||||
{ x : 10, z : 20, _ : [], $0 : './usage' }
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
r.errors.join('\n').split(/\n+/).join('\n'),
|
||||
'Usage: ./usage -x NUM -y NUM\n'
|
||||
+ 'Argument check failed: ' + checker.toString()
|
||||
);
|
||||
|
||||
assert.deepEqual(r.logs, []);
|
||||
assert.ok(r.exit);
|
||||
};
|
||||
|
||||
exports.countPass = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('1 2 3 --moo'.split(' '))
|
||||
.usage('Usage: $0 [x] [y] [z] {OPTIONS}')
|
||||
.demand(3)
|
||||
.argv;
|
||||
});
|
||||
assert.deepEqual(r, {
|
||||
result : { _ : [ '1', '2', '3' ], moo : true, $0 : './usage' },
|
||||
errors : [],
|
||||
logs : [],
|
||||
exit : false,
|
||||
});
|
||||
};
|
||||
|
||||
exports.countFail = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('1 2 --moo'.split(' '))
|
||||
.usage('Usage: $0 [x] [y] [z] {OPTIONS}')
|
||||
.demand(3)
|
||||
.argv;
|
||||
});
|
||||
assert.deepEqual(
|
||||
r.result,
|
||||
{ _ : [ '1', '2' ], moo : true, $0 : './usage' }
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
r.errors.join('\n').split(/\n+/),
|
||||
[
|
||||
'Usage: ./usage [x] [y] [z] {OPTIONS}',
|
||||
'Not enough non-option arguments: got 2, need at least 3',
|
||||
]
|
||||
);
|
||||
|
||||
assert.deepEqual(r.logs, []);
|
||||
assert.ok(r.exit);
|
||||
};
|
||||
|
||||
exports.defaultSingles = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('--foo 50 --baz 70 --powsy'.split(' '))
|
||||
.default('foo', 5)
|
||||
.default('bar', 6)
|
||||
.default('baz', 7)
|
||||
.argv
|
||||
;
|
||||
});
|
||||
assert.eql(r.result, {
|
||||
foo : '50',
|
||||
bar : 6,
|
||||
baz : '70',
|
||||
powsy : true,
|
||||
_ : [],
|
||||
$0 : './usage',
|
||||
});
|
||||
};
|
||||
|
||||
exports.defaultHash = function () {
|
||||
var r = checkUsage(function () {
|
||||
return optimist('--foo 50 --baz 70'.split(' '))
|
||||
.default({ foo : 10, bar : 20, quux : 30 })
|
||||
.argv
|
||||
;
|
||||
});
|
||||
assert.eql(r.result, {
|
||||
foo : '50',
|
||||
bar : 20,
|
||||
baz : 70,
|
||||
quux : 30,
|
||||
_ : [],
|
||||
$0 : './usage',
|
||||
});
|
||||
};
|
||||
|
||||
exports.rebase = function () {
|
||||
assert.equal(
|
||||
optimist.rebase('/home/substack', '/home/substack/foo/bar/baz'),
|
||||
'./foo/bar/baz'
|
||||
);
|
||||
assert.equal(
|
||||
optimist.rebase('/home/substack/foo/bar/baz', '/home/substack'),
|
||||
'../../..'
|
||||
);
|
||||
assert.equal(
|
||||
optimist.rebase('/home/substack/foo', '/home/substack/pow/zoom.txt'),
|
||||
'../pow/zoom.txt'
|
||||
);
|
||||
};
|
||||
|
||||
function checkUsage (f) {
|
||||
var _process = process;
|
||||
process = Hash.copy(process);
|
||||
var exit = false;
|
||||
process.exit = function () { exit = true };
|
||||
process.env = Hash.merge(process.env, { _ : 'node' });
|
||||
process.argv = [ './usage' ];
|
||||
|
||||
var errors = [];
|
||||
var logs = [];
|
||||
|
||||
console._error = console.error;
|
||||
console.error = function (msg) { errors.push(msg) };
|
||||
console._log = console.log;
|
||||
console.log = function (msg) { logs.push(msg) };
|
||||
|
||||
var result = f();
|
||||
|
||||
process = _process;
|
||||
console.error = console._error;
|
||||
console.log = console._log;
|
||||
|
||||
return {
|
||||
errors : errors,
|
||||
logs : logs,
|
||||
exit : exit,
|
||||
result : result,
|
||||
};
|
||||
};
|
||||
+45
-7
@@ -1,16 +1,54 @@
|
||||
{
|
||||
"author": "Craig Condon <craig.j.condon@gmail.com>",
|
||||
"author": "Jared Allard <jaredallard@outlook.com>",
|
||||
"name": "nexe",
|
||||
"description": "Roll node.s applications into a single executable",
|
||||
"version": "0.0.1",
|
||||
"description": "create single executables out of your [node/io].js applications",
|
||||
"license": "MIT",
|
||||
"version": "1.0.7",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Criag Condon",
|
||||
"email": "craig.j.condon@gmail.com",
|
||||
"url": "http://crcn.io/"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/crcn/nexe.git"
|
||||
"url": "git://github.com/jaredallard/nexe.git"
|
||||
},
|
||||
"main": "./lib/index.js",
|
||||
"dependencies": {
|
||||
"optimist":"*",
|
||||
"sardines":"*"
|
||||
"async": "1.5.2",
|
||||
"browserify": "^13.0.0",
|
||||
"builtins": "1.0.3",
|
||||
"colors": "^1.1.2",
|
||||
"glob": "^6.0.4",
|
||||
"insert-module-globals": "^7.0.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"module-deps": "^4.0.5",
|
||||
"ncp": "^2.0.0",
|
||||
"outcome": "0.0.18",
|
||||
"progress": "^1.1.8",
|
||||
"request": "^2.67.0",
|
||||
"sprintf": "~0.1.5",
|
||||
"step": "0.0.x",
|
||||
"tar.gz": "1.0.2",
|
||||
"yargs": "^3.32.0"
|
||||
},
|
||||
"devDependencies": {}
|
||||
"nexe": {
|
||||
"input": "./bin/nexe",
|
||||
"output": "nexe^$",
|
||||
"temp": "src",
|
||||
"runtime": {
|
||||
"framework": "nodejs",
|
||||
"version": "5.5.0",
|
||||
"ignoreFlags": true
|
||||
}
|
||||
},
|
||||
"preferGlobal": true,
|
||||
"bin": {
|
||||
"nexe": "./bin/nexe"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodeunit": "^0.9.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"build_systems":
|
||||
[
|
||||
{
|
||||
"name":"cbd make",
|
||||
"cmd":["cbd","make","nexe"]
|
||||
},
|
||||
{
|
||||
"name":"cbd start",
|
||||
"cmd":["cbd","start","nexe"]
|
||||
},
|
||||
{
|
||||
"name":"cbd make+start",
|
||||
"cmd":["cbd","make+start","nexe"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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']);
|
||||
@@ -0,0 +1 @@
|
||||
console.log('Hello, world!');
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user