├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── example ├── example-promise.js └── example.js ├── index.js ├── package-lock.json ├── package.json ├── src ├── command.js ├── common.js ├── index.js ├── machine.js ├── parsers.js └── provisioners.js ├── templates ├── basic.tpl ├── commands.tpl └── name-value.tpl └── test ├── command-test.js ├── data ├── box-no-box-installed.txt ├── box-outdated.txt ├── boxes.txt ├── global-status.txt ├── integration │ ├── Vagrantfile │ ├── example1.Vagrantfile │ ├── example1.config.json │ ├── example2.Vagrantfile │ └── example2.config.json ├── provision.shell.sh ├── ssh-config-nokey.txt ├── ssh-config.txt └── status ├── helpers.js ├── index-test.js ├── integration-test.js ├── machine-test.js ├── parsers-test.js └── provisioners-test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.{js,json}] 14 | charset = utf-8 15 | 16 | # 4 space indentation 17 | [*.js] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # Matches the exact files either package.json 22 | [{package.json}] 23 | indent_style = space 24 | indent_size = 2 25 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "es6": false 5 | }, 6 | "extends": "eslint:recommended", 7 | "globals": { 8 | "describe": true, 9 | "it": true, 10 | "before": true, 11 | "beforeEach": true, 12 | "after": true, 13 | "afterEach": true 14 | }, 15 | "rules": { 16 | // indent 4 spaces 17 | "indent": [ 18 | 2, 19 | 4, 20 | { 21 | "SwitchCase": 1 22 | } 23 | ], 24 | // use unix lf - and warn if not 25 | "linebreak-style": [ 26 | 1, 27 | "unix" 28 | ], 29 | // prefer single quote 30 | "quotes": [ 31 | 1, 32 | "single" 33 | ], 34 | // prefer semi-colon at the end of the line 35 | "semi": 1, 36 | // prefer comma at the end of the line in objects, arrays, etc 37 | "comma-dangle": [ 38 | 1, 39 | "only-multiline" 40 | ], 41 | // if then else on new lines 42 | "brace-style": [ 43 | "error", 44 | "1tbs" 45 | ], 46 | // prefer spaces around the keywords 47 | "keyword-spacing": [ 48 | 1 49 | ], 50 | // don't disallow console statements 51 | "no-console": "off", 52 | // enforce curly braces 53 | "curly": 2, 54 | // prefer comments with space 55 | "spaced-comment": 1, 56 | // don't disallow var keyword 57 | "no-var": 0, 58 | // warn on capitalized function names 59 | "new-cap": 1, 60 | // space before blocks mandatory 61 | "space-before-blocks": 2, 62 | // prefer space before function param parenthisis only when anonymous 63 | "space-before-function-paren": [ 64 | 1, 65 | { 66 | "anonymous": "always", 67 | "named": "never" 68 | } 69 | ], 70 | // require end-of-file newline 71 | "eol-last": 2, 72 | // warn unnecessary escapes 73 | "no-useless-escape": 1, 74 | // disallow padding within blocks 75 | "padded-blocks": [2, "never"], 76 | // no spaces in brackets 77 | "array-bracket-spacing": 1, 78 | // yes to spaces in braces 79 | "object-curly-spacing": [1, "always"] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | example/Vagrantfile 4 | example/.vagrant 5 | node_modules 6 | test/Vagrantfile 7 | .idea 8 | .DS_Store 9 | .vagrant 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | - "11" 5 | - "12" 6 | - "13" 7 | - "14" 8 | - "15" 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, edin-m <> 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-vagrant 2 | Node js wrapper for vagrant CLI - command line tool. 3 | 4 | This is light wrapper around vagrant CLI. 5 | It uses spawn process, and every command requiring user input 6 | such as init and destroy is created with switch --force or -f. 7 | 8 | [![npm version](https://badge.fury.io/js/node-vagrant.svg)](https://badge.fury.io/js/node-vagrant) 9 | [![Build Status](https://travis-ci.org/edin-m/node-vagrant.svg?branch=master)](https://travis-ci.org/edin-m/node-vagrant) 10 | 11 | Installation 12 | === 13 | 14 | ``` 15 | $ npm install node-vagrant --save 16 | ``` 17 | 18 | Usage 19 | === 20 | 21 | All callbacks are node style: 22 | ```js 23 | function(err, out) 24 | ``` 25 | where err is stderr if exit code != 0 and out is stdout if exit code == 0 26 | ___ 27 | Other commands 28 | ```js 29 | // import vagrant 30 | var vagrant = require('node-vagrant'); 31 | 32 | // view version 33 | vagrant.version(function(err, out) {}); 34 | // or --version ; out = { status: '2.0.3', major: 2, minor: 0, patch: 3 } 35 | vagrant.versionStatus(function(err, out) {}); 36 | 37 | // view global status 38 | // you can specify '--prune' as additional argument. By default global-status is based on a cache, 39 | // prune removes invalid entries from the list. 40 | // Note that this is much more time consuming than simply listing the entries. 41 | vagrant.globalStatus(function(err, out) {}); 42 | vagrant.globalStatus('--prune', function(err, out) {}); 43 | 44 | // vagrant machine 45 | 46 | // create machine - does not run command or init machine 47 | // you can specify directory where Vagrantfile will be located 48 | // and machine instanced 49 | var machine = vagrant.create({ cwd: , env: }) // cwd and env default to process' values 50 | 51 | // init machine 52 | // you can specify additional arguments by using array (applicable to other functions) 53 | machine.init('ubuntu/trusty64', function(err, out) {}); 54 | machine.init(['ubuntu/trusty64'], function(err, out) {}); 55 | // -f is set by default 56 | machine.init(['ubuntu/trusty64', '-f'], function(err, out) {}); 57 | 58 | // up 59 | machine.up(function(err, out) {}) 60 | 61 | // status 62 | machine.status(function(err, out) {}); 63 | 64 | // get ssh config - useful to retrieve private and connect to machine with ssh2 65 | // out is an array of objects [{}] with properties: port, hostname, user, private_key 66 | machine.sshConfig(function(err, out) {}); 67 | 68 | // execute an ssh command on the machine 69 | machine.on('ssh-out', console.log); 70 | machine.on('ssh-err', console.error); 71 | machine.sshCommand('echo "a bash command"'); 72 | 73 | // provision 74 | machine.provision(function(err, out) {}); 75 | 76 | // suspend 77 | machine.suspend(function(err, out) {}); 78 | 79 | // resume 80 | machine.resume(function(err, out) {}); 81 | 82 | // reload 83 | machine.reload(function(err, out) {}); 84 | 85 | // halt 86 | machine.halt(function(err, out) {}); 87 | 88 | // destroy 89 | // uses -f by default 90 | machine.destroy(function(err, out) {}); 91 | 92 | // snapshots 93 | // push, pop, save, delete, restore, list and a snapshot() function. 94 | // example: 95 | machine.snapshots().push(cb); 96 | 97 | // box repackage 98 | // must be specific to a vagrant environment hence location in machine 99 | machine.boxRepackage(name, provider, version, function(err, out) {}) 100 | 101 | // plugins 102 | // expunge, install, uninstall, repair, update, list and a plugin() function. 103 | // example: 104 | machine.plugin().expunge(args, cb); 105 | 106 | // DEPRECATED! For backward compatibility only 107 | machine.pluginUpdate(function(err, out) {}); 108 | machine.pluginRepair(function(err, out) {}); 109 | 110 | // boxes 111 | 112 | // box add 113 | // uses -f by default 114 | // depending on type of box provided (name,address,file,json) missing information may be prompted. 115 | // please ensure that your add metheod is specific. 116 | vagrant.boxAdd(box, args, function(err, out) {}) 117 | .on('progress', function(out) {}); 118 | 119 | // box list 120 | // out is an array of objects [{}] with properties: name, provider, version 121 | vagrant.boxList(args, function(err, out) {}); 122 | 123 | // box outdated 124 | // --global is used by default 125 | // out is an array of objects [{}] with properties: name, status, currentVersion, latestVersion 126 | // status can be 'up to date' 'out of date' 'unknown' 127 | // if status is unknown currentVersion and latestVersion will be null 128 | vagrant.boxOutdated(args, function(err, out) {}); 129 | 130 | // box prune 131 | // uses -f by defaultprune 132 | vagrant.boxPrune(args, function(err, out) {}); 133 | 134 | // box remove 135 | // uses -f by default 136 | vagrant.boxRemove(name, args, function(err, out) {}); 137 | 138 | // box repackage 139 | // avalible in machine 140 | 141 | // box update 142 | // uses the --box and --provider flags by default 143 | // provider can be null and in that case no --provider arg is added 144 | vagrant.boxUpdate(box, provider, function(err, out) {}); 145 | .on('progress', function(out) {}); 146 | 147 | 148 | // args 149 | // should be array of args or a string for single flag see --prune abov 150 | // ie 151 | vagrant.boxAdd('ubuntu/trusty64', ['--clean', '--provider', 'virtualbox'], function(err, out) {}) 152 | //or simply 153 | vagrant.boxAdd('ubuntu/trusty64', '--clean', function(err, out) {}) 154 | ``` 155 | 156 | Events 157 | === 158 | ```js 159 | .on('up-progress', function(out) {}); // receive stdout progress from up of vagrant 160 | 161 | .on('progress', function(out) {}); // receive stdout box download progress 162 | ``` 163 | 164 | Receive any stdout/stderr output from a child subprocess. These work only on a Machine instance: 165 | 166 | ``` 167 | machine.on('stdout', function(data) {}); // data is a Buffer 168 | machine.on('stderr', function(data) {}); // data is a Buffer 169 | ``` 170 | 171 | Example 172 | === 173 | 174 | Example script of a usage is in example/example.js 175 | 176 | ``` 177 | $ npm run example 178 | ``` 179 | 180 | Flags & env vars 181 | === 182 | 183 | Debug the commands sent to vagrant: 184 | ```js 185 | $ NODE_DEBUG=1 node example.js 186 | node-vagrant command: [ 'global-status' ] 187 | node-vagrant command: [ 'version' ] 188 | ``` 189 | 190 | Disable the debug: 191 | ```js 192 | $ NODE_DEBUG=1 NODE_VAGRANT_DISABLE_DEBUG=1 node example.js 193 | ``` 194 | 195 | Custom vagrant location: 196 | ```js 197 | $ VAGRANT_DIR=/custom/path node example.js 198 | ``` 199 | 200 | Promises 201 | === 202 | 203 | ```js 204 | var vagrant = require('../index'); 205 | vagrant.promisify(); 206 | 207 | vagrant.init('ubuntu/trusty64').then(successCb, errorCb); 208 | ``` 209 | 210 | TODO 211 | === 212 | - [ ] multi-machine 213 | - [ ] more detail vagrant file settings 214 | - [ ] firewall 215 | - [ ] networking 216 | - [x] boxing 217 | - [x] provisoning 218 | - [x] providers 219 | - [x] (native) promises (if available) 220 | - [ ] use ES6 (after which will become version 2.x.x) 221 | -------------------------------------------------------------------------------- /example/example-promise.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | var vagrant = require('../index'); 5 | vagrant.promisify(); 6 | 7 | process.env.NODE_DEBUG = true; 8 | 9 | vagrant.globalStatus().then(console.log.bind(console)); 10 | 11 | vagrant.version().then(console.log.bind(console)); 12 | 13 | vagrant.versionStatus().then(console.log.bind(console)); 14 | 15 | var machine = vagrant.create({ cwd: process.cwd(), env: process.env }); 16 | 17 | machine.on('progress', function () { 18 | console.log('download progress: ', [].slice.call(arguments)); 19 | }); 20 | 21 | machine.on('up-progress', function () { 22 | console.log('up progress: ', [].slice.call(arguments)); 23 | }); 24 | 25 | var config = { 26 | config: { 27 | vm: { 28 | box: 'ubuntu/trusty64' 29 | } 30 | } 31 | }; 32 | 33 | machine.init('ubuntu/trusty64', config) 34 | .then(function (out) { 35 | return machine.up(); 36 | }, function (err) { 37 | throw new Error(err); 38 | }) 39 | .then(function (out) { 40 | return machine.status(); 41 | }, function (err) { 42 | throw new Error(err); 43 | }) 44 | .then(function (out) { 45 | console.log(out); 46 | return machine.sshConfig(); 47 | }) 48 | .then(function (out) { 49 | console.log(out); 50 | return machine.suspend(); 51 | }) 52 | .then(function (out) { 53 | console.log(out); 54 | return machine.resume(); 55 | }) 56 | .then(function (out) { 57 | console.log(out); 58 | return machine.halt(); 59 | }) 60 | .then(function (out) { 61 | console.log(out); 62 | return machine.destroy(); 63 | }) 64 | .then(function (out) { 65 | console.log(out); 66 | return vagrant.globalStatus(); 67 | }) 68 | .then(function (out) { 69 | console.log(out); 70 | fs.unlinkSync('./Vagrantfile'); 71 | }) 72 | .catch(function (err) { 73 | console.log('Caught an error\n', err); 74 | }); 75 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | var vagrant = require('../index'); 5 | 6 | process.env.NODE_DEBUG = true; 7 | 8 | vagrant.globalStatus(function (err, out) { 9 | console.log(err, out); 10 | }); 11 | 12 | vagrant.version(function (err, out) { 13 | console.log(err, out); 14 | }); 15 | 16 | vagrant.versionStatus(function (err, out) { 17 | console.log(err, out); 18 | }); 19 | 20 | var machine = vagrant.create({ cwd: process.cwd(), env: process.env }); 21 | 22 | function onInit(err, out) { 23 | if (err) { 24 | throw new Error(err); 25 | } 26 | 27 | /* eslint no-unused-vars: ["error", { "args": "none" }] */ 28 | 29 | machine.on('progress', function () { 30 | console.log('download progress: ', [].slice.call(arguments)); 31 | }); 32 | 33 | machine.on('up-progress', function () { 34 | console.log('up progress: ', [].slice.call(arguments)); 35 | }); 36 | 37 | machine.up(function (err, out) { 38 | if (err) { 39 | throw new Error(err); 40 | } 41 | 42 | machine.status(function (err, out) { 43 | console.log(err, out); 44 | 45 | machine.sshConfig(function (err, out) { 46 | console.log(err, out); 47 | 48 | machine.suspend(function (err, out) { 49 | console.log(err, out); 50 | 51 | machine.resume(function (err, out) { 52 | console.log(err, out); 53 | 54 | machine.halt(function (err, out) { 55 | console.log(err, out); 56 | 57 | machine.destroy(function (err, out) { 58 | console.log(err, out); 59 | 60 | vagrant.globalStatus(function (err, out) { 61 | console.log(err, out); 62 | }); 63 | 64 | fs.unlinkSync('./Vagrantfile'); 65 | }); 66 | }); 67 | }); 68 | }); 69 | }); 70 | }); 71 | }); 72 | } 73 | 74 | // adv config: 75 | // var config = { 76 | // config: { 77 | // vm: { 78 | // box: 'ubuntu/trusty64' 79 | // } 80 | // } 81 | // }; 82 | // machine.init('ubuntu/trusty64', config, onInit); 83 | 84 | machine.init('ubuntu/trusty64', onInit); 85 | 86 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src'); 2 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-vagrant", 3 | "version": "1.5.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.12.11", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 10 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.10.4" 14 | } 15 | }, 16 | "@babel/helper-validator-identifier": { 17 | "version": "7.12.11", 18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", 19 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", 20 | "dev": true 21 | }, 22 | "@babel/highlight": { 23 | "version": "7.10.4", 24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", 25 | "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", 26 | "dev": true, 27 | "requires": { 28 | "@babel/helper-validator-identifier": "^7.10.4", 29 | "chalk": "^2.0.0", 30 | "js-tokens": "^4.0.0" 31 | } 32 | }, 33 | "@sinonjs/commons": { 34 | "version": "1.4.0", 35 | "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", 36 | "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", 37 | "dev": true, 38 | "requires": { 39 | "type-detect": "4.0.8" 40 | }, 41 | "dependencies": { 42 | "type-detect": { 43 | "version": "4.0.8", 44 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 45 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 46 | "dev": true 47 | } 48 | } 49 | }, 50 | "@sinonjs/samsam": { 51 | "version": "3.3.1", 52 | "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.1.tgz", 53 | "integrity": "sha512-wRSfmyd81swH0hA1bxJZJ57xr22kC07a1N4zuIL47yTS04bDk6AoCkczcqHEjcRPmJ+FruGJ9WBQiJwMtIElFw==", 54 | "dev": true, 55 | "requires": { 56 | "@sinonjs/commons": "^1.0.2", 57 | "array-from": "^2.1.1", 58 | "lodash": "^4.17.11" 59 | } 60 | }, 61 | "@sinonjs/text-encoding": { 62 | "version": "0.7.1", 63 | "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", 64 | "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", 65 | "dev": true 66 | }, 67 | "acorn": { 68 | "version": "7.4.1", 69 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 70 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 71 | "dev": true 72 | }, 73 | "acorn-jsx": { 74 | "version": "5.3.1", 75 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", 76 | "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", 77 | "dev": true 78 | }, 79 | "ajv": { 80 | "version": "6.12.6", 81 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 82 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 83 | "dev": true, 84 | "requires": { 85 | "fast-deep-equal": "^3.1.1", 86 | "fast-json-stable-stringify": "^2.0.0", 87 | "json-schema-traverse": "^0.4.1", 88 | "uri-js": "^4.2.2" 89 | } 90 | }, 91 | "ansi-escapes": { 92 | "version": "4.3.1", 93 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", 94 | "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", 95 | "dev": true, 96 | "requires": { 97 | "type-fest": "^0.11.0" 98 | }, 99 | "dependencies": { 100 | "type-fest": { 101 | "version": "0.11.0", 102 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", 103 | "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", 104 | "dev": true 105 | } 106 | } 107 | }, 108 | "ansi-regex": { 109 | "version": "5.0.0", 110 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 111 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 112 | "dev": true 113 | }, 114 | "ansi-styles": { 115 | "version": "3.2.1", 116 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 117 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 118 | "dev": true, 119 | "requires": { 120 | "color-convert": "^1.9.0" 121 | } 122 | }, 123 | "argparse": { 124 | "version": "1.0.10", 125 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 126 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 127 | "dev": true, 128 | "requires": { 129 | "sprintf-js": "~1.0.2" 130 | } 131 | }, 132 | "array-from": { 133 | "version": "2.1.1", 134 | "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", 135 | "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", 136 | "dev": true 137 | }, 138 | "assertion-error": { 139 | "version": "1.0.0", 140 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", 141 | "integrity": "sha1-x/hUOP3UZrx8oWq5DIFRN5el0js=", 142 | "dev": true 143 | }, 144 | "astral-regex": { 145 | "version": "1.0.0", 146 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 147 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", 148 | "dev": true 149 | }, 150 | "balanced-match": { 151 | "version": "1.0.0", 152 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 153 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 154 | "dev": true 155 | }, 156 | "brace-expansion": { 157 | "version": "1.1.11", 158 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 159 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 160 | "dev": true, 161 | "requires": { 162 | "balanced-match": "^1.0.0", 163 | "concat-map": "0.0.1" 164 | } 165 | }, 166 | "browser-stdout": { 167 | "version": "1.3.1", 168 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 169 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 170 | "dev": true 171 | }, 172 | "callsites": { 173 | "version": "3.1.0", 174 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 175 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 176 | "dev": true 177 | }, 178 | "chai": { 179 | "version": "2.1.0", 180 | "resolved": "https://registry.npmjs.org/chai/-/chai-2.1.0.tgz", 181 | "integrity": "sha1-fIdTiVsD7u8r8j8PnkX++kPuT8w=", 182 | "dev": true, 183 | "requires": { 184 | "assertion-error": "1.0.0", 185 | "deep-eql": "0.1.3" 186 | } 187 | }, 188 | "chalk": { 189 | "version": "2.4.2", 190 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 191 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 192 | "dev": true, 193 | "requires": { 194 | "ansi-styles": "^3.2.1", 195 | "escape-string-regexp": "^1.0.5", 196 | "supports-color": "^5.3.0" 197 | } 198 | }, 199 | "chardet": { 200 | "version": "0.7.0", 201 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 202 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", 203 | "dev": true 204 | }, 205 | "cli-cursor": { 206 | "version": "3.1.0", 207 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", 208 | "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", 209 | "dev": true, 210 | "requires": { 211 | "restore-cursor": "^3.1.0" 212 | } 213 | }, 214 | "cli-width": { 215 | "version": "3.0.0", 216 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", 217 | "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", 218 | "dev": true 219 | }, 220 | "color-convert": { 221 | "version": "1.9.3", 222 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 223 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 224 | "dev": true, 225 | "requires": { 226 | "color-name": "1.1.3" 227 | } 228 | }, 229 | "color-name": { 230 | "version": "1.1.3", 231 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 232 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 233 | "dev": true 234 | }, 235 | "commander": { 236 | "version": "2.15.1", 237 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 238 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 239 | "dev": true 240 | }, 241 | "concat-map": { 242 | "version": "0.0.1", 243 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 244 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 245 | "dev": true 246 | }, 247 | "cross-spawn": { 248 | "version": "6.0.5", 249 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 250 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 251 | "dev": true, 252 | "requires": { 253 | "nice-try": "^1.0.4", 254 | "path-key": "^2.0.1", 255 | "semver": "^5.5.0", 256 | "shebang-command": "^1.2.0", 257 | "which": "^1.2.9" 258 | }, 259 | "dependencies": { 260 | "semver": { 261 | "version": "5.7.1", 262 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 263 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 264 | "dev": true 265 | } 266 | } 267 | }, 268 | "debug": { 269 | "version": "3.1.0", 270 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 271 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 272 | "dev": true, 273 | "requires": { 274 | "ms": "2.0.0" 275 | } 276 | }, 277 | "deep-eql": { 278 | "version": "0.1.3", 279 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", 280 | "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", 281 | "dev": true, 282 | "requires": { 283 | "type-detect": "0.1.1" 284 | } 285 | }, 286 | "deep-is": { 287 | "version": "0.1.3", 288 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 289 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 290 | "dev": true 291 | }, 292 | "diff": { 293 | "version": "3.5.0", 294 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 295 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 296 | "dev": true 297 | }, 298 | "doctrine": { 299 | "version": "3.0.0", 300 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 301 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 302 | "dev": true, 303 | "requires": { 304 | "esutils": "^2.0.2" 305 | } 306 | }, 307 | "emoji-regex": { 308 | "version": "8.0.0", 309 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 310 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 311 | "dev": true 312 | }, 313 | "escape-string-regexp": { 314 | "version": "1.0.5", 315 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 316 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 317 | "dev": true 318 | }, 319 | "eslint": { 320 | "version": "6.8.0", 321 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", 322 | "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", 323 | "dev": true, 324 | "requires": { 325 | "@babel/code-frame": "^7.0.0", 326 | "ajv": "^6.10.0", 327 | "chalk": "^2.1.0", 328 | "cross-spawn": "^6.0.5", 329 | "debug": "^4.0.1", 330 | "doctrine": "^3.0.0", 331 | "eslint-scope": "^5.0.0", 332 | "eslint-utils": "^1.4.3", 333 | "eslint-visitor-keys": "^1.1.0", 334 | "espree": "^6.1.2", 335 | "esquery": "^1.0.1", 336 | "esutils": "^2.0.2", 337 | "file-entry-cache": "^5.0.1", 338 | "functional-red-black-tree": "^1.0.1", 339 | "glob-parent": "^5.0.0", 340 | "globals": "^12.1.0", 341 | "ignore": "^4.0.6", 342 | "import-fresh": "^3.0.0", 343 | "imurmurhash": "^0.1.4", 344 | "inquirer": "^7.0.0", 345 | "is-glob": "^4.0.0", 346 | "js-yaml": "^3.13.1", 347 | "json-stable-stringify-without-jsonify": "^1.0.1", 348 | "levn": "^0.3.0", 349 | "lodash": "^4.17.14", 350 | "minimatch": "^3.0.4", 351 | "mkdirp": "^0.5.1", 352 | "natural-compare": "^1.4.0", 353 | "optionator": "^0.8.3", 354 | "progress": "^2.0.0", 355 | "regexpp": "^2.0.1", 356 | "semver": "^6.1.2", 357 | "strip-ansi": "^5.2.0", 358 | "strip-json-comments": "^3.0.1", 359 | "table": "^5.2.3", 360 | "text-table": "^0.2.0", 361 | "v8-compile-cache": "^2.0.3" 362 | }, 363 | "dependencies": { 364 | "debug": { 365 | "version": "4.3.1", 366 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 367 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 368 | "dev": true, 369 | "requires": { 370 | "ms": "2.1.2" 371 | } 372 | }, 373 | "ms": { 374 | "version": "2.1.2", 375 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 376 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 377 | "dev": true 378 | } 379 | } 380 | }, 381 | "eslint-scope": { 382 | "version": "5.1.1", 383 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 384 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 385 | "dev": true, 386 | "requires": { 387 | "esrecurse": "^4.3.0", 388 | "estraverse": "^4.1.1" 389 | } 390 | }, 391 | "eslint-utils": { 392 | "version": "1.4.3", 393 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", 394 | "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", 395 | "dev": true, 396 | "requires": { 397 | "eslint-visitor-keys": "^1.1.0" 398 | } 399 | }, 400 | "eslint-visitor-keys": { 401 | "version": "1.3.0", 402 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 403 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 404 | "dev": true 405 | }, 406 | "espree": { 407 | "version": "6.2.1", 408 | "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", 409 | "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", 410 | "dev": true, 411 | "requires": { 412 | "acorn": "^7.1.1", 413 | "acorn-jsx": "^5.2.0", 414 | "eslint-visitor-keys": "^1.1.0" 415 | } 416 | }, 417 | "esprima": { 418 | "version": "4.0.1", 419 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 420 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 421 | "dev": true 422 | }, 423 | "esquery": { 424 | "version": "1.3.1", 425 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", 426 | "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", 427 | "dev": true, 428 | "requires": { 429 | "estraverse": "^5.1.0" 430 | }, 431 | "dependencies": { 432 | "estraverse": { 433 | "version": "5.2.0", 434 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 435 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 436 | "dev": true 437 | } 438 | } 439 | }, 440 | "esrecurse": { 441 | "version": "4.3.0", 442 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 443 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 444 | "dev": true, 445 | "requires": { 446 | "estraverse": "^5.2.0" 447 | }, 448 | "dependencies": { 449 | "estraverse": { 450 | "version": "5.2.0", 451 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 452 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 453 | "dev": true 454 | } 455 | } 456 | }, 457 | "estraverse": { 458 | "version": "4.3.0", 459 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 460 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 461 | "dev": true 462 | }, 463 | "esutils": { 464 | "version": "2.0.3", 465 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 466 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 467 | "dev": true 468 | }, 469 | "external-editor": { 470 | "version": "3.1.0", 471 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", 472 | "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", 473 | "dev": true, 474 | "requires": { 475 | "chardet": "^0.7.0", 476 | "iconv-lite": "^0.4.24", 477 | "tmp": "^0.0.33" 478 | } 479 | }, 480 | "fast-deep-equal": { 481 | "version": "3.1.3", 482 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 483 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 484 | "dev": true 485 | }, 486 | "fast-json-stable-stringify": { 487 | "version": "2.1.0", 488 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 489 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 490 | "dev": true 491 | }, 492 | "fast-levenshtein": { 493 | "version": "2.0.6", 494 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 495 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 496 | "dev": true 497 | }, 498 | "figures": { 499 | "version": "3.2.0", 500 | "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", 501 | "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", 502 | "dev": true, 503 | "requires": { 504 | "escape-string-regexp": "^1.0.5" 505 | } 506 | }, 507 | "file-entry-cache": { 508 | "version": "5.0.1", 509 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 510 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", 511 | "dev": true, 512 | "requires": { 513 | "flat-cache": "^2.0.1" 514 | } 515 | }, 516 | "flat-cache": { 517 | "version": "2.0.1", 518 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", 519 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", 520 | "dev": true, 521 | "requires": { 522 | "flatted": "^2.0.0", 523 | "rimraf": "2.6.3", 524 | "write": "1.0.3" 525 | } 526 | }, 527 | "flatted": { 528 | "version": "2.0.2", 529 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", 530 | "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", 531 | "dev": true 532 | }, 533 | "formatio": { 534 | "version": "1.2.0", 535 | "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", 536 | "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", 537 | "dev": true, 538 | "requires": { 539 | "samsam": "1.x" 540 | } 541 | }, 542 | "fs.realpath": { 543 | "version": "1.0.0", 544 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 545 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 546 | "dev": true 547 | }, 548 | "functional-red-black-tree": { 549 | "version": "1.0.1", 550 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 551 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 552 | "dev": true 553 | }, 554 | "glob": { 555 | "version": "7.1.2", 556 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 557 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 558 | "dev": true, 559 | "requires": { 560 | "fs.realpath": "^1.0.0", 561 | "inflight": "^1.0.4", 562 | "inherits": "2", 563 | "minimatch": "^3.0.4", 564 | "once": "^1.3.0", 565 | "path-is-absolute": "^1.0.0" 566 | } 567 | }, 568 | "glob-parent": { 569 | "version": "5.1.1", 570 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 571 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 572 | "dev": true, 573 | "requires": { 574 | "is-glob": "^4.0.1" 575 | } 576 | }, 577 | "globals": { 578 | "version": "12.4.0", 579 | "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", 580 | "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", 581 | "dev": true, 582 | "requires": { 583 | "type-fest": "^0.8.1" 584 | } 585 | }, 586 | "growl": { 587 | "version": "1.10.5", 588 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 589 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 590 | "dev": true 591 | }, 592 | "has-flag": { 593 | "version": "3.0.0", 594 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 595 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 596 | "dev": true 597 | }, 598 | "he": { 599 | "version": "1.1.1", 600 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 601 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 602 | "dev": true 603 | }, 604 | "iconv-lite": { 605 | "version": "0.4.24", 606 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 607 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 608 | "dev": true, 609 | "requires": { 610 | "safer-buffer": ">= 2.1.2 < 3" 611 | } 612 | }, 613 | "ignore": { 614 | "version": "4.0.6", 615 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 616 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 617 | "dev": true 618 | }, 619 | "import-fresh": { 620 | "version": "3.3.0", 621 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 622 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 623 | "dev": true, 624 | "requires": { 625 | "parent-module": "^1.0.0", 626 | "resolve-from": "^4.0.0" 627 | } 628 | }, 629 | "imurmurhash": { 630 | "version": "0.1.4", 631 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 632 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 633 | "dev": true 634 | }, 635 | "inflight": { 636 | "version": "1.0.6", 637 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 638 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 639 | "dev": true, 640 | "requires": { 641 | "once": "^1.3.0", 642 | "wrappy": "1" 643 | } 644 | }, 645 | "inherits": { 646 | "version": "2.0.3", 647 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 648 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 649 | "dev": true 650 | }, 651 | "inquirer": { 652 | "version": "7.3.3", 653 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", 654 | "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", 655 | "dev": true, 656 | "requires": { 657 | "ansi-escapes": "^4.2.1", 658 | "chalk": "^4.1.0", 659 | "cli-cursor": "^3.1.0", 660 | "cli-width": "^3.0.0", 661 | "external-editor": "^3.0.3", 662 | "figures": "^3.0.0", 663 | "lodash": "^4.17.19", 664 | "mute-stream": "0.0.8", 665 | "run-async": "^2.4.0", 666 | "rxjs": "^6.6.0", 667 | "string-width": "^4.1.0", 668 | "strip-ansi": "^6.0.0", 669 | "through": "^2.3.6" 670 | }, 671 | "dependencies": { 672 | "ansi-styles": { 673 | "version": "4.3.0", 674 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 675 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 676 | "dev": true, 677 | "requires": { 678 | "color-convert": "^2.0.1" 679 | } 680 | }, 681 | "chalk": { 682 | "version": "4.1.0", 683 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 684 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 685 | "dev": true, 686 | "requires": { 687 | "ansi-styles": "^4.1.0", 688 | "supports-color": "^7.1.0" 689 | } 690 | }, 691 | "color-convert": { 692 | "version": "2.0.1", 693 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 694 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 695 | "dev": true, 696 | "requires": { 697 | "color-name": "~1.1.4" 698 | } 699 | }, 700 | "color-name": { 701 | "version": "1.1.4", 702 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 703 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 704 | "dev": true 705 | }, 706 | "has-flag": { 707 | "version": "4.0.0", 708 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 709 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 710 | "dev": true 711 | }, 712 | "strip-ansi": { 713 | "version": "6.0.0", 714 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 715 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 716 | "dev": true, 717 | "requires": { 718 | "ansi-regex": "^5.0.0" 719 | } 720 | }, 721 | "supports-color": { 722 | "version": "7.2.0", 723 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 724 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 725 | "dev": true, 726 | "requires": { 727 | "has-flag": "^4.0.0" 728 | } 729 | } 730 | } 731 | }, 732 | "is-extglob": { 733 | "version": "2.1.1", 734 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 735 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 736 | "dev": true 737 | }, 738 | "is-fullwidth-code-point": { 739 | "version": "3.0.0", 740 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 741 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 742 | "dev": true 743 | }, 744 | "is-glob": { 745 | "version": "4.0.1", 746 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 747 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 748 | "dev": true, 749 | "requires": { 750 | "is-extglob": "^2.1.1" 751 | } 752 | }, 753 | "isarray": { 754 | "version": "0.0.1", 755 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 756 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 757 | "dev": true 758 | }, 759 | "isexe": { 760 | "version": "2.0.0", 761 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 762 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 763 | "dev": true 764 | }, 765 | "js-tokens": { 766 | "version": "4.0.0", 767 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 768 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 769 | "dev": true 770 | }, 771 | "js-yaml": { 772 | "version": "3.14.1", 773 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 774 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 775 | "dev": true, 776 | "requires": { 777 | "argparse": "^1.0.7", 778 | "esprima": "^4.0.0" 779 | } 780 | }, 781 | "json-schema-traverse": { 782 | "version": "0.4.1", 783 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 784 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 785 | "dev": true 786 | }, 787 | "json-stable-stringify-without-jsonify": { 788 | "version": "1.0.1", 789 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 790 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 791 | "dev": true 792 | }, 793 | "levn": { 794 | "version": "0.3.0", 795 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 796 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 797 | "dev": true, 798 | "requires": { 799 | "prelude-ls": "~1.1.2", 800 | "type-check": "~0.3.2" 801 | } 802 | }, 803 | "lodash": { 804 | "version": "4.17.19", 805 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", 806 | "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" 807 | }, 808 | "lolex": { 809 | "version": "2.7.1", 810 | "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.1.tgz", 811 | "integrity": "sha512-Oo2Si3RMKV3+lV5MsSWplDQFoTClz/24S0MMHYcgGWWmFXr6TMlqcqk/l1GtH+d5wLBwNRiqGnwDRMirtFalJw==", 812 | "dev": true 813 | }, 814 | "mimic-fn": { 815 | "version": "2.1.0", 816 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 817 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 818 | "dev": true 819 | }, 820 | "minimatch": { 821 | "version": "3.0.4", 822 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 823 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 824 | "dev": true, 825 | "requires": { 826 | "brace-expansion": "^1.1.7" 827 | } 828 | }, 829 | "minimist": { 830 | "version": "0.0.8", 831 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 832 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 833 | "dev": true 834 | }, 835 | "mkdirp": { 836 | "version": "0.5.1", 837 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 838 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 839 | "dev": true, 840 | "requires": { 841 | "minimist": "0.0.8" 842 | } 843 | }, 844 | "mocha": { 845 | "version": "5.2.0", 846 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 847 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 848 | "dev": true, 849 | "requires": { 850 | "browser-stdout": "1.3.1", 851 | "commander": "2.15.1", 852 | "debug": "3.1.0", 853 | "diff": "3.5.0", 854 | "escape-string-regexp": "1.0.5", 855 | "glob": "7.1.2", 856 | "growl": "1.10.5", 857 | "he": "1.1.1", 858 | "minimatch": "3.0.4", 859 | "mkdirp": "0.5.1", 860 | "supports-color": "5.4.0" 861 | }, 862 | "dependencies": { 863 | "escape-string-regexp": { 864 | "version": "1.0.5", 865 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 866 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 867 | "dev": true 868 | } 869 | } 870 | }, 871 | "ms": { 872 | "version": "2.0.0", 873 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 874 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 875 | "dev": true 876 | }, 877 | "mute-stream": { 878 | "version": "0.0.8", 879 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", 880 | "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", 881 | "dev": true 882 | }, 883 | "native-promise-only": { 884 | "version": "0.8.1", 885 | "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", 886 | "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", 887 | "dev": true 888 | }, 889 | "natural-compare": { 890 | "version": "1.4.0", 891 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 892 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 893 | "dev": true 894 | }, 895 | "nice-try": { 896 | "version": "1.0.5", 897 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 898 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 899 | "dev": true 900 | }, 901 | "nise": { 902 | "version": "1.4.10", 903 | "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.10.tgz", 904 | "integrity": "sha512-sa0RRbj53dovjc7wombHmVli9ZihXbXCQ2uH3TNm03DyvOSIQbxg+pbqDKrk2oxMK1rtLGVlKxcB9rrc6X5YjA==", 905 | "dev": true, 906 | "requires": { 907 | "@sinonjs/formatio": "^3.1.0", 908 | "@sinonjs/text-encoding": "^0.7.1", 909 | "just-extend": "^4.0.2", 910 | "lolex": "^2.3.2", 911 | "path-to-regexp": "^1.7.0" 912 | }, 913 | "dependencies": { 914 | "@sinonjs/formatio": { 915 | "version": "3.2.1", 916 | "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", 917 | "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", 918 | "dev": true, 919 | "requires": { 920 | "@sinonjs/commons": "^1", 921 | "@sinonjs/samsam": "^3.1.0" 922 | } 923 | }, 924 | "just-extend": { 925 | "version": "4.0.2", 926 | "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", 927 | "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", 928 | "dev": true 929 | } 930 | } 931 | }, 932 | "once": { 933 | "version": "1.4.0", 934 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 935 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 936 | "dev": true, 937 | "requires": { 938 | "wrappy": "1" 939 | } 940 | }, 941 | "onetime": { 942 | "version": "5.1.2", 943 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 944 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 945 | "dev": true, 946 | "requires": { 947 | "mimic-fn": "^2.1.0" 948 | } 949 | }, 950 | "optionator": { 951 | "version": "0.8.3", 952 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", 953 | "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", 954 | "dev": true, 955 | "requires": { 956 | "deep-is": "~0.1.3", 957 | "fast-levenshtein": "~2.0.6", 958 | "levn": "~0.3.0", 959 | "prelude-ls": "~1.1.2", 960 | "type-check": "~0.3.2", 961 | "word-wrap": "~1.2.3" 962 | } 963 | }, 964 | "os-tmpdir": { 965 | "version": "1.0.2", 966 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 967 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 968 | "dev": true 969 | }, 970 | "parent-module": { 971 | "version": "1.0.1", 972 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 973 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 974 | "dev": true, 975 | "requires": { 976 | "callsites": "^3.0.0" 977 | } 978 | }, 979 | "path-is-absolute": { 980 | "version": "1.0.1", 981 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 982 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 983 | "dev": true 984 | }, 985 | "path-key": { 986 | "version": "2.0.1", 987 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 988 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 989 | "dev": true 990 | }, 991 | "path-to-regexp": { 992 | "version": "1.7.0", 993 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", 994 | "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", 995 | "dev": true, 996 | "requires": { 997 | "isarray": "0.0.1" 998 | } 999 | }, 1000 | "prelude-ls": { 1001 | "version": "1.1.2", 1002 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1003 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1004 | "dev": true 1005 | }, 1006 | "progress": { 1007 | "version": "2.0.3", 1008 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1009 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1010 | "dev": true 1011 | }, 1012 | "punycode": { 1013 | "version": "2.1.1", 1014 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1015 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1016 | "dev": true 1017 | }, 1018 | "regexpp": { 1019 | "version": "2.0.1", 1020 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", 1021 | "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", 1022 | "dev": true 1023 | }, 1024 | "resolve-from": { 1025 | "version": "4.0.0", 1026 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1027 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1028 | "dev": true 1029 | }, 1030 | "restore-cursor": { 1031 | "version": "3.1.0", 1032 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", 1033 | "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", 1034 | "dev": true, 1035 | "requires": { 1036 | "onetime": "^5.1.0", 1037 | "signal-exit": "^3.0.2" 1038 | } 1039 | }, 1040 | "rewire": { 1041 | "version": "5.0.0", 1042 | "resolved": "https://registry.npmjs.org/rewire/-/rewire-5.0.0.tgz", 1043 | "integrity": "sha512-1zfitNyp9RH5UDyGGLe9/1N0bMlPQ0WrX0Tmg11kMHBpqwPJI4gfPpP7YngFyLbFmhXh19SToAG0sKKEFcOIJA==", 1044 | "dev": true, 1045 | "requires": { 1046 | "eslint": "^6.8.0" 1047 | } 1048 | }, 1049 | "rimraf": { 1050 | "version": "2.6.3", 1051 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1052 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 1053 | "dev": true, 1054 | "requires": { 1055 | "glob": "^7.1.3" 1056 | }, 1057 | "dependencies": { 1058 | "glob": { 1059 | "version": "7.1.6", 1060 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 1061 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 1062 | "dev": true, 1063 | "requires": { 1064 | "fs.realpath": "^1.0.0", 1065 | "inflight": "^1.0.4", 1066 | "inherits": "2", 1067 | "minimatch": "^3.0.4", 1068 | "once": "^1.3.0", 1069 | "path-is-absolute": "^1.0.0" 1070 | } 1071 | } 1072 | } 1073 | }, 1074 | "run-async": { 1075 | "version": "2.4.1", 1076 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", 1077 | "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", 1078 | "dev": true 1079 | }, 1080 | "rxjs": { 1081 | "version": "6.6.3", 1082 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", 1083 | "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", 1084 | "dev": true, 1085 | "requires": { 1086 | "tslib": "^1.9.0" 1087 | } 1088 | }, 1089 | "safer-buffer": { 1090 | "version": "2.1.2", 1091 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1092 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1093 | "dev": true 1094 | }, 1095 | "samsam": { 1096 | "version": "1.3.0", 1097 | "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", 1098 | "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", 1099 | "dev": true 1100 | }, 1101 | "semver": { 1102 | "version": "6.3.0", 1103 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1104 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1105 | "dev": true 1106 | }, 1107 | "shebang-command": { 1108 | "version": "1.2.0", 1109 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1110 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1111 | "dev": true, 1112 | "requires": { 1113 | "shebang-regex": "^1.0.0" 1114 | } 1115 | }, 1116 | "shebang-regex": { 1117 | "version": "1.0.0", 1118 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1119 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1120 | "dev": true 1121 | }, 1122 | "signal-exit": { 1123 | "version": "3.0.3", 1124 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 1125 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 1126 | "dev": true 1127 | }, 1128 | "sinon": { 1129 | "version": "3.2.0", 1130 | "resolved": "https://registry.npmjs.org/sinon/-/sinon-3.2.0.tgz", 1131 | "integrity": "sha512-Jg2Bcp+X5L0d5bMQqQzMPMh/oZ/TwwcgbVG5Z4xRPxKYqWYw75O6m4LrEhrQdOE10RsoaEQMwTFNn4rHjTyKew==", 1132 | "dev": true, 1133 | "requires": { 1134 | "diff": "^3.1.0", 1135 | "formatio": "1.2.0", 1136 | "lolex": "^2.1.2", 1137 | "native-promise-only": "^0.8.1", 1138 | "nise": "^1.0.1", 1139 | "path-to-regexp": "^1.7.0", 1140 | "samsam": "^1.1.3", 1141 | "text-encoding": "0.6.4", 1142 | "type-detect": "^4.0.0" 1143 | }, 1144 | "dependencies": { 1145 | "diff": { 1146 | "version": "3.5.0", 1147 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 1148 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 1149 | "dev": true 1150 | }, 1151 | "type-detect": { 1152 | "version": "4.0.8", 1153 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1154 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1155 | "dev": true 1156 | } 1157 | } 1158 | }, 1159 | "slice-ansi": { 1160 | "version": "2.1.0", 1161 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 1162 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", 1163 | "dev": true, 1164 | "requires": { 1165 | "ansi-styles": "^3.2.0", 1166 | "astral-regex": "^1.0.0", 1167 | "is-fullwidth-code-point": "^2.0.0" 1168 | }, 1169 | "dependencies": { 1170 | "is-fullwidth-code-point": { 1171 | "version": "2.0.0", 1172 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1173 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1174 | "dev": true 1175 | } 1176 | } 1177 | }, 1178 | "sprintf-js": { 1179 | "version": "1.0.3", 1180 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1181 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1182 | "dev": true 1183 | }, 1184 | "string-width": { 1185 | "version": "4.2.0", 1186 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 1187 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 1188 | "dev": true, 1189 | "requires": { 1190 | "emoji-regex": "^8.0.0", 1191 | "is-fullwidth-code-point": "^3.0.0", 1192 | "strip-ansi": "^6.0.0" 1193 | }, 1194 | "dependencies": { 1195 | "strip-ansi": { 1196 | "version": "6.0.0", 1197 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1198 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1199 | "dev": true, 1200 | "requires": { 1201 | "ansi-regex": "^5.0.0" 1202 | } 1203 | } 1204 | } 1205 | }, 1206 | "strip-ansi": { 1207 | "version": "5.2.0", 1208 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1209 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1210 | "dev": true, 1211 | "requires": { 1212 | "ansi-regex": "^4.1.0" 1213 | }, 1214 | "dependencies": { 1215 | "ansi-regex": { 1216 | "version": "4.1.0", 1217 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1218 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1219 | "dev": true 1220 | } 1221 | } 1222 | }, 1223 | "strip-json-comments": { 1224 | "version": "3.1.1", 1225 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1226 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1227 | "dev": true 1228 | }, 1229 | "supports-color": { 1230 | "version": "5.4.0", 1231 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 1232 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 1233 | "dev": true, 1234 | "requires": { 1235 | "has-flag": "^3.0.0" 1236 | } 1237 | }, 1238 | "table": { 1239 | "version": "5.4.6", 1240 | "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", 1241 | "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", 1242 | "dev": true, 1243 | "requires": { 1244 | "ajv": "^6.10.2", 1245 | "lodash": "^4.17.14", 1246 | "slice-ansi": "^2.1.0", 1247 | "string-width": "^3.0.0" 1248 | }, 1249 | "dependencies": { 1250 | "emoji-regex": { 1251 | "version": "7.0.3", 1252 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 1253 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 1254 | "dev": true 1255 | }, 1256 | "is-fullwidth-code-point": { 1257 | "version": "2.0.0", 1258 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1259 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1260 | "dev": true 1261 | }, 1262 | "string-width": { 1263 | "version": "3.1.0", 1264 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1265 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1266 | "dev": true, 1267 | "requires": { 1268 | "emoji-regex": "^7.0.1", 1269 | "is-fullwidth-code-point": "^2.0.0", 1270 | "strip-ansi": "^5.1.0" 1271 | } 1272 | } 1273 | } 1274 | }, 1275 | "text-encoding": { 1276 | "version": "0.6.4", 1277 | "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", 1278 | "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", 1279 | "dev": true 1280 | }, 1281 | "text-table": { 1282 | "version": "0.2.0", 1283 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1284 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1285 | "dev": true 1286 | }, 1287 | "through": { 1288 | "version": "2.3.8", 1289 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1290 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1291 | "dev": true 1292 | }, 1293 | "tmp": { 1294 | "version": "0.0.33", 1295 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1296 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1297 | "dev": true, 1298 | "requires": { 1299 | "os-tmpdir": "~1.0.2" 1300 | } 1301 | }, 1302 | "tslib": { 1303 | "version": "1.14.1", 1304 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 1305 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 1306 | "dev": true 1307 | }, 1308 | "type-check": { 1309 | "version": "0.3.2", 1310 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1311 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1312 | "dev": true, 1313 | "requires": { 1314 | "prelude-ls": "~1.1.2" 1315 | } 1316 | }, 1317 | "type-detect": { 1318 | "version": "0.1.1", 1319 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", 1320 | "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", 1321 | "dev": true 1322 | }, 1323 | "type-fest": { 1324 | "version": "0.8.1", 1325 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 1326 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 1327 | "dev": true 1328 | }, 1329 | "uri-js": { 1330 | "version": "4.4.0", 1331 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", 1332 | "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", 1333 | "dev": true, 1334 | "requires": { 1335 | "punycode": "^2.1.0" 1336 | } 1337 | }, 1338 | "v8-compile-cache": { 1339 | "version": "2.2.0", 1340 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", 1341 | "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", 1342 | "dev": true 1343 | }, 1344 | "which": { 1345 | "version": "1.3.1", 1346 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1347 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1348 | "dev": true, 1349 | "requires": { 1350 | "isexe": "^2.0.0" 1351 | } 1352 | }, 1353 | "word-wrap": { 1354 | "version": "1.2.3", 1355 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 1356 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 1357 | "dev": true 1358 | }, 1359 | "wrappy": { 1360 | "version": "1.0.2", 1361 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1362 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1363 | "dev": true 1364 | }, 1365 | "write": { 1366 | "version": "1.0.3", 1367 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", 1368 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", 1369 | "dev": true, 1370 | "requires": { 1371 | "mkdirp": "^0.5.1" 1372 | } 1373 | } 1374 | } 1375 | } 1376 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-vagrant", 3 | "version": "1.5.0", 4 | "description": "Node js wrapper for vagrant CLI - command line tool.", 5 | "main": "index.js", 6 | "keywords": [ 7 | "vagrant" 8 | ], 9 | "scripts": { 10 | "example": "cd example && node example.js", 11 | "test": "node ./node_modules/mocha/bin/mocha test", 12 | "test-all": "export RUN_INTEGRATION_TESTS=1 && node ./node_modules/mocha/bin/mocha test", 13 | "lint": "eslint src/ test/ index.js" 14 | }, 15 | "author": { 16 | "name": "Edin Mujagic" 17 | }, 18 | "contributors": [ 19 | { 20 | "name": "Maximilian Klein", 21 | "url": "https://github.com/LittleHelicase" 22 | }, 23 | { 24 | "name": "Jacob Payne", 25 | "url": "https://github.com/Latrasis" 26 | }, 27 | { 28 | "name": "Friedemann Stoffregen", 29 | "url": "https://github.com/Donderda" 30 | }, 31 | { 32 | "name": "Leonardo Nahra", 33 | "url": "https://github.com/lanahra" 34 | }, 35 | { 36 | "name": "Tyler Stiene", 37 | "url": "https://github.com/Stieneee" 38 | } 39 | ], 40 | "repository": { 41 | "type": "git", 42 | "url": "https://github.com/edin-m/node-vagrant.git" 43 | }, 44 | "bugs": { 45 | "url": "https://github.com/edin-m/node-vagrant/issues" 46 | }, 47 | "homepage": "https://github.com/edin-m/node-vagrant", 48 | "license": "ISC", 49 | "dependencies": { 50 | "lodash": "4.17.19" 51 | }, 52 | "devDependencies": { 53 | "chai": "2.1.0", 54 | "mocha": "5.2.0", 55 | "sinon": "3.2.0", 56 | "rewire": "5.0.0" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/command.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | var spawn = child_process.spawn; 3 | var path = require('path'); 4 | 5 | var vagrant = process.env.VAGRANT_DIR ? path.join(process.env.VAGRANT_DIR, 'vagrant') : 'vagrant'; 6 | 7 | function buildCommand(name, args, more) { 8 | more = more || []; 9 | 10 | if (!args || (typeof args === 'function')) { 11 | args = []; 12 | } 13 | 14 | if (!Array.isArray(args)) { 15 | args = [args]; 16 | } 17 | 18 | args = args.concat(more); 19 | 20 | if (!Array.isArray(name)) { 21 | name = [name]; 22 | } 23 | 24 | return name.concat(args); 25 | } 26 | 27 | function runCommand(command, opts, cb) { 28 | var args = [].slice.call(arguments); 29 | 30 | if (args.length === 1) { 31 | opts = {}; 32 | } else if (args.length === 2) { 33 | if (typeof args[1] === 'function') { 34 | cb = opts; 35 | opts = {}; 36 | } 37 | } 38 | 39 | if (!Array.isArray(command)) { 40 | command = buildCommand(command); 41 | } 42 | 43 | if (process.env.NODE_DEBUG && !process.env.NODE_VAGRANT_DISABLE_DEBUG) { 44 | console.log('node-vagrant command:', command); 45 | } 46 | 47 | opts.detached = false; 48 | var child = spawn(vagrant, command, opts); 49 | 50 | if (typeof cb === 'function') { 51 | var out = ''; 52 | var err = ''; 53 | 54 | child.stdout.on('data', function (data) { 55 | out += data; 56 | }); 57 | 58 | child.stderr.on('data', function (data) { 59 | err += data; 60 | }); 61 | 62 | child.on('close', function (code) { 63 | if (code !== 0) { 64 | return cb(err, out); 65 | } 66 | return cb(null, out); 67 | }); 68 | 69 | child.on('error', function (err) { 70 | return cb(err); 71 | }); 72 | } 73 | 74 | return child; 75 | } 76 | 77 | module.exports = { 78 | buildCommand: buildCommand, 79 | runCommand: runCommand 80 | }; 81 | -------------------------------------------------------------------------------- /src/common.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | var _isPromiseEnabled = false; 4 | 5 | function enablePromised() { 6 | _isPromiseEnabled = true; 7 | } 8 | 9 | function isPromised() { 10 | return _isPromiseEnabled && typeof Promise === 'function' && 11 | typeof util.promisify === 'function'; 12 | } 13 | 14 | module.exports = { 15 | enablePromised: enablePromised, 16 | isPromised: isPromised 17 | }; 18 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events').EventEmitter; 2 | var util = require('util'); 3 | 4 | var parsers = require('./parsers'); 5 | var Command = require('./command'); 6 | var Machine = require('./machine'); 7 | var Common = require('./common'); 8 | 9 | module.exports._run = Command.runCommand; 10 | 11 | module.exports.Machine = Machine; 12 | 13 | module.exports.globalStatus = function (args, cb) { 14 | cb = cb || args; 15 | 16 | var command = Command.buildCommand('global-status', args); 17 | module.exports._run(command, function (err, out) { 18 | if (err) { 19 | return cb(err); 20 | } 21 | var lines = parsers.globalStatusParser(out); 22 | cb(null, lines); 23 | }); 24 | }; 25 | 26 | module.exports.create = function (opts) { 27 | return new Machine(opts); 28 | }; 29 | 30 | module.exports.version = function (cb) { 31 | module.exports._run(Command.buildCommand('version'), cb); 32 | }; 33 | 34 | module.exports.versionStatus = function (cb) { 35 | var command = Command.buildCommand('--version'); 36 | module.exports._run(command, function (err, out) { 37 | if (err) { 38 | return cb(err); 39 | } 40 | cb(null, parsers.versionStatusParser(out)); 41 | }); 42 | }; 43 | 44 | module.exports.boxAdd = function (box, args, cb) { 45 | cb = cb || args; 46 | if (typeof box !== 'string' && cb) { 47 | return cb('box must be provided as a string'); 48 | } 49 | 50 | var command = Command.buildCommand(['box', 'add', '-f'], args, box); 51 | var proc = module.exports._run(command, cb); 52 | 53 | var emitter = new EventEmitter; 54 | proc.stdout.on('data', function (buff) { 55 | var data = buff.toString(); 56 | 57 | var res = parsers.downloadStatusParser(data); 58 | if (res) { 59 | emitter.emit('progress', res.machine, res.progress, res.rate, res.remaining); 60 | } 61 | }); 62 | return emitter; 63 | }; 64 | 65 | module.exports.boxList = function (args, cb) { 66 | cb = cb || args; 67 | 68 | var command = Command.buildCommand(['box', 'list'], args); 69 | module.exports._run(command, function (err, out) { 70 | if (err) { 71 | return cb(err); 72 | } 73 | cb(null, parsers.boxListParser(out)); 74 | }); 75 | }; 76 | 77 | module.exports.boxOutdated = function (args, cb) { 78 | cb = cb || args; 79 | 80 | var command = Command.buildCommand(['box', 'outdated', '--global'], args); 81 | module.exports._run(command, function (err, out) { 82 | if (err) { 83 | return cb(err); 84 | } 85 | cb(null, parsers.boxListOutdatedParser(out)); 86 | }); 87 | }; 88 | 89 | module.exports.boxPrune = function (args, cb) { 90 | cb = cb || args; 91 | 92 | var command = Command.buildCommand(['box', 'prune', '-f'], args); 93 | module.exports._run(command, cb); 94 | }; 95 | 96 | module.exports.boxRemove = function (name, args, cb) { 97 | if (typeof name !== 'string' && cb) { 98 | return cb('name must be provided as a string'); 99 | } 100 | 101 | cb = cb || args; 102 | 103 | var command = Command.buildCommand(['box', 'remove', '-f'], args, name); 104 | module.exports._run(command, cb); 105 | }; 106 | 107 | module.exports.boxUpdate = function (box, provider, cb) { 108 | if (typeof box !== 'string' && cb) { 109 | cb('box must be provided as a string'); 110 | return new EventEmitter; 111 | } 112 | 113 | var commandArgs = ['box', 'update', '--box', box]; 114 | if (typeof provider === 'string') { 115 | commandArgs.push('--provider'); 116 | commandArgs.push(provider); 117 | } 118 | 119 | var command = Command.buildCommand(commandArgs); 120 | var proc = module.exports._run(command, cb); 121 | 122 | var emitter = new EventEmitter; 123 | proc.stdout.on('data', function (buff) { 124 | var data = buff.toString(); 125 | 126 | var res = parsers.downloadStatusParser(data); 127 | if (res) { 128 | emitter.emit('progress', res.machine, res.progress, res.rate, res.remaining); 129 | } 130 | }); 131 | return emitter; 132 | }; 133 | 134 | module.exports.promisify = function () { 135 | Common.enablePromised(); 136 | if (Common.isPromised()) { 137 | Machine.promisify(); 138 | module.exports.globalStatus = util.promisify(module.exports.globalStatus); 139 | module.exports.version = util.promisify(module.exports.version); 140 | module.exports.versionStatus = util.promisify(module.exports.versionStatus); 141 | module.exports.boxAdd = util.promisify(module.exports.boxAdd); 142 | module.exports.boxList = util.promisify(module.exports.boxList); 143 | module.exports.boxOutdated = util.promisify(module.exports.boxOutdated); 144 | module.exports.boxPrune = util.promisify(module.exports.boxPrune); 145 | module.exports.boxRemove = util.promisify(module.exports.boxRemove); 146 | module.exports.boxUpdate = util.promisify(module.exports.boxUpdate); 147 | } else { 148 | console.error('No Promise top-level class found'); 149 | } 150 | }; 151 | -------------------------------------------------------------------------------- /src/machine.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events').EventEmitter; 2 | var util = require('util'); 3 | var path = require('path'); 4 | var _ = require('lodash'); 5 | var fs = require('fs'); 6 | 7 | var provisionerAdapters = require('./provisioners'); 8 | var parsers = require('./parsers'); 9 | var Command = require('./command'); 10 | var Common = require('./common'); 11 | 12 | function Machine(opts) { 13 | opts = opts || {}; 14 | 15 | if (!(this instanceof Machine)) { 16 | return new Machine(opts); 17 | } 18 | 19 | this.batch = []; 20 | 21 | this.opts = opts; 22 | this.opts.cwd = this.opts.cwd || process.cwd(); 23 | this.opts.env = this.opts.env || process.env; 24 | } 25 | 26 | util.inherits(Machine, EventEmitter); 27 | 28 | Machine.prototype._run = function (command, cb) { 29 | var self = this; 30 | if (self._runningCommand) { 31 | self.batch.push({ command: command, cb: cb }); 32 | return; 33 | } 34 | 35 | self._runningCommand = true; 36 | 37 | // var out = ''; 38 | // var err = ''; 39 | var child = Command.runCommand(command, { 40 | cwd: self.opts.cwd, 41 | env: self.opts.env 42 | }, function (err, data) { 43 | self._runningCommand = false; 44 | var next = self.batch.pop(); 45 | if (next) { 46 | self._run(next.command, next.cb); 47 | } 48 | 49 | if (typeof cb === 'function') { 50 | cb(err, data); 51 | } 52 | }); 53 | 54 | if (!!child.stdout) { 55 | child.stdout.on('data', function (data) { 56 | self.emit('stdout', data); 57 | }); 58 | } 59 | 60 | if (!!child.stderr) { 61 | child.stderr.on('data', function (data) { 62 | self.emit('stderr', data); 63 | }); 64 | } 65 | 66 | return child; 67 | }; 68 | 69 | Machine.prototype.sshConfig = function (cb) { 70 | var command = Command.buildCommand('ssh-config'); 71 | 72 | this._run(command, function (err, out) { 73 | if (err) { 74 | return cb(err); 75 | } 76 | var configs = parsers.sshConfigParser(out); 77 | cb(null, configs); 78 | }); 79 | }; 80 | 81 | Machine.prototype.sshCommand = function (cmd, cb) { 82 | var command = Command.buildCommand('ssh', ['-c', cmd]); 83 | var proc = this._run(command, cb); 84 | 85 | var self = this; 86 | proc.stdout.on('data', function (buff) { 87 | self.emit('ssh-out', buff.toString()); 88 | }); 89 | 90 | proc.stderr.on('data', function(buff) { 91 | self.emit('ssh-err', buff.toString()); 92 | }); 93 | }; 94 | 95 | Machine.prototype.status = function (cb) { 96 | var command = Command.buildCommand('status'); 97 | 98 | this._run(command, function (err, out) { 99 | if (err) { 100 | return cb(err); 101 | } 102 | var statuses = parsers.statusParser(out); 103 | cb(null, statuses); 104 | }); 105 | }; 106 | 107 | Machine.prototype.up = function (args, cb) { 108 | cb = cb || args; 109 | 110 | var command = Command.buildCommand('up', args); 111 | var proc = this._run(command, cb); 112 | 113 | var self = this; 114 | proc.stdout.on('data', function (buff) { 115 | var data = buff.toString(); 116 | 117 | self.emit('up-progress', data); 118 | 119 | var res = parsers.downloadStatusParser(data); 120 | if (res) { 121 | self.emit('progress', res.machine, res.progress, res.rate, res.remaining); 122 | } 123 | }); 124 | }; 125 | 126 | Machine.prototype._changeVagrantfile = function (config, cb) { 127 | var self = this; 128 | 129 | var where = path.join(__dirname, '../templates/basic.tpl'); 130 | var locVagrantfile = path.join(self.opts.cwd, 'Vagrantfile'); 131 | fs.readFile(where, function (err, data) { 132 | if (err) { 133 | return cb(err); 134 | } 135 | 136 | data = data.toString(); 137 | 138 | var compiled = _.template(data); 139 | var rendered = compiled(config); 140 | 141 | fs.writeFile(locVagrantfile, rendered, function (err) { 142 | if (err) { 143 | return cb(err); 144 | } 145 | cb(null); 146 | }); 147 | }); 148 | }; 149 | 150 | /** 151 | * Transforms provisioner config to array and appends additional configuration 152 | */ 153 | Machine.prototype._prepareProvisioners = function (config) { 154 | if (!config.provisioners) { 155 | config.provisioners = {}; 156 | } 157 | if (_.isObject(config.provisioners) && !_.isArray(config.provisioners)) { 158 | // convert provisioners to array and add name and type 159 | var provisioners = config.provisioners; 160 | config.provisioners = Object.keys(provisioners).reduce(function (prev, name) { 161 | return prev.concat([{ 162 | name: name, 163 | type: name, 164 | config: provisioners[name] 165 | }]); 166 | }, []); 167 | } 168 | config.provisioners.forEach(function (provisioner) { 169 | provisioner.templateLines = provisionerAdapters.createTemplate(provisioner).split(/\n|\r/).map(function (item) { 170 | return item.trim(); 171 | }).filter(function (item) { 172 | return item.length > 0; 173 | }); 174 | }); 175 | }; 176 | 177 | Machine.prototype.init = function (args, config, cb) { 178 | cb = cb || config; 179 | config = typeof config === 'object' ? config : {}; 180 | 181 | var command = Command.buildCommand('init', args, ['-f']); 182 | 183 | var self = this; 184 | 185 | // make config in form of { config: { ... } } 186 | if (!_.isEmpty(config) && !config.hasOwnProperty('config')) { 187 | var newconfig = config; 188 | config = {}; 189 | config.config = newconfig; 190 | } 191 | 192 | if (!config.config) { 193 | config.config = { 194 | vm: { box: args } 195 | }; 196 | } 197 | 198 | self._prepareProvisioners(config.config); 199 | 200 | if (!_.isEmpty(config)) { 201 | this._run(command, function (err, res) { 202 | self._changeVagrantfile(config, function (err) { 203 | if (err) { 204 | return cb(err); 205 | } 206 | cb(null, res); 207 | }); 208 | }); 209 | } else { 210 | this._run(command, cb); 211 | } 212 | }; 213 | 214 | Machine.prototype.destroy = function (args, cb) { 215 | cb = cb || args; 216 | this._generic(['destroy', '-f'], args, cb); 217 | }; 218 | 219 | Machine.prototype.suspend = function (cb) { 220 | this._generic('suspend', [], cb); 221 | }; 222 | 223 | Machine.prototype.resume = function (cb) { 224 | this._generic('resume', [], cb); 225 | }; 226 | 227 | Machine.prototype.halt = function (args, cb) { 228 | cb = cb || args; 229 | this._generic(['halt', '-f'], args, cb); 230 | }; 231 | 232 | Machine.prototype.reload = function (args, cb) { 233 | cb = cb || args; 234 | this._generic('reload', args, cb); 235 | }; 236 | 237 | Machine.prototype.provision = function (cb) { 238 | this._generic('provision', [], cb); 239 | }; 240 | 241 | Machine.prototype.pluginUpdate = function (cb) { 242 | console.warn('DEPRECATED, use plugin().update()'); 243 | this._generic('plugin update', [], cb); 244 | }; 245 | 246 | Machine.prototype.pluginRepair = function (cb) { 247 | console.warn('DEPRECATED, use plugin().repair()'); 248 | this._generic('plugin repair', [], cb); 249 | }; 250 | 251 | Machine.prototype.plugin = function () { 252 | var self = this; 253 | var plugin = { 254 | expunge: function (args, cb) { 255 | self._generic('plugin', 'expunge', args, cb); 256 | }, 257 | install: function (args, cb) { 258 | self._generic('plugin', 'install', args, cb); 259 | }, 260 | uninstall: function (args, cb) { 261 | self._generic('plugin', 'uninstall', args, cb); 262 | }, 263 | list: function (args, cb) { 264 | self._generic('plugin', 'list', args, cb); 265 | }, 266 | repair: function (args, cb) { 267 | self._generic('plugin', 'repair', args, cb); 268 | }, 269 | update: function (args, cb) { 270 | self._generic('plugin', 'update', args, cb); 271 | } 272 | }; 273 | if (Common.isPromised()) { 274 | plugin.expunge = util.promisify(plugin.expunge); 275 | plugin.install = util.promisify(plugin.install); 276 | plugin.uninstall = util.promisify(plugin.uninstall); 277 | plugin.list = util.promisify(plugin.list); 278 | plugin.repair = util.promisify(plugin.repair); 279 | plugin.update = util.promisify(plugin.update); 280 | } 281 | return plugin; 282 | }; 283 | 284 | Machine.prototype.snapshots = function () { 285 | var self = this; 286 | var snapshots = { 287 | push: function (cb) { 288 | self._generic('snapshot', 'push', cb); 289 | }, 290 | pop: function (cb) { 291 | self._generic('snapshot', 'pop', cb); 292 | }, 293 | save: function (args, cb) { 294 | self._generic('snapshot save', args, cb); 295 | }, 296 | restore: function (args, cb) { 297 | self._generic('snapshot restore', args, cb); 298 | }, 299 | list: function (cb) { 300 | self._generic('snapshot', 'list', cb); 301 | }, 302 | delete: function (args, cb) { 303 | self._generic('snapshot delete', args, cb); 304 | } 305 | }; 306 | if (Common.isPromised()) { 307 | snapshots.push = util.promisify(snapshots.push); 308 | snapshots.pop = util.promisify(snapshots.pop); 309 | snapshots.save = util.promisify(snapshots.save); 310 | snapshots.restore = util.promisify(snapshots.restore); 311 | snapshots.list = util.promisify(snapshots.list); 312 | snapshots.delete = util.promisify(snapshots.delete); 313 | } 314 | return snapshots; 315 | }; 316 | 317 | Machine.prototype.boxRepackage = function (name, provider, version, cb) { 318 | if (typeof name !== 'string') { 319 | return cb('name must be provided as a string'); 320 | } 321 | if (typeof provider !== 'string') { 322 | return cb('provider must be provided as a string'); 323 | } 324 | if (typeof version !== 'string') { 325 | return cb('version must be provided as a string'); 326 | } 327 | 328 | var command = Command.buildCommand(['box', 'repackage', name, provider, version]); 329 | this._run(command, cb); 330 | }; 331 | 332 | Machine.prototype._generic = function (name, args, cb) { 333 | this._run(Command.buildCommand(name, args), cb); 334 | }; 335 | 336 | /** 337 | * 338 | */ 339 | module.exports = Machine; 340 | 341 | module.exports.promisify = function () { 342 | if (Common.isPromised()) { 343 | Machine.prototype.sshConfig = util.promisify(Machine.prototype.sshConfig); 344 | Machine.prototype.sshCommand = util.promisify(Machine.prototype.sshCommand); 345 | Machine.prototype.status = util.promisify(Machine.prototype.status); 346 | Machine.prototype.up = util.promisify(Machine.prototype.up); 347 | Machine.prototype.init = util.promisify(Machine.prototype.init); 348 | Machine.prototype.destroy = util.promisify(Machine.prototype.destroy); 349 | Machine.prototype.suspend = util.promisify(Machine.prototype.suspend); 350 | Machine.prototype.resume = util.promisify(Machine.prototype.resume); 351 | Machine.prototype.halt = util.promisify(Machine.prototype.halt); 352 | Machine.prototype.reload = util.promisify(Machine.prototype.reload); 353 | Machine.prototype.provision = util.promisify(Machine.prototype.provision); 354 | Machine.prototype.boxRepackage = util.promisify(Machine.prototype.boxRepackage); 355 | } 356 | }; 357 | -------------------------------------------------------------------------------- /src/parsers.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | var MATCHERS = { 4 | download: /(\S+): Progress: (\d{1,2})% \(Rate: ([\dmgks\/]+), Estimated time remaining: ([\d\-:]+)\)/i, 5 | versionStatus: /Vagrant (([\d]+).([\d]+).([\d]+))/ 6 | }; 7 | 8 | var SSH_CONFIG_MATCHERS = { 9 | host: /Host (\S+)$/mi, 10 | port: /Port (\S+)$/mi, 11 | hostname: /HostName (\S+)$/mi, 12 | user: /User (\S+)$/mi, 13 | private_key: /IdentityFile (\S+)$/mi, 14 | }; 15 | 16 | var BOX_LIST_MATCHERS = { 17 | name: /^.*?(?=\s)/, 18 | provider: /[^(]+(?=,)/, 19 | version: /\S+(?=\))/, 20 | }; 21 | 22 | /** 23 | * 24 | */ 25 | function downloadStatusParser(data) { 26 | var res = data.match(MATCHERS.download); 27 | if (res) { 28 | return { 29 | machine: res[1], 30 | progress: res[2], 31 | rate: res[3], 32 | remaining: res[4] 33 | }; 34 | } 35 | return null; 36 | } 37 | 38 | function findArrayContainsStringIndex(str, array) { 39 | for (var i = 0; i < array.length; i++) { 40 | if (str.test(array[i])) { 41 | return i; 42 | } 43 | } 44 | return -1; 45 | } 46 | 47 | /** 48 | * 49 | */ 50 | function statusParser(statusText) { 51 | var lines = statusText.split('\n'); 52 | var startIndex = findArrayContainsStringIndex(/Current machine states/, lines); 53 | lines = lines.slice(startIndex).slice(2).reduce(function (prev, curr) { 54 | if (prev.length > 0 && prev[prev.length - 1].length === 0) { 55 | return prev; 56 | } 57 | 58 | prev.push(curr.trim()); 59 | return prev; 60 | }, []); 61 | 62 | lines.pop(); 63 | 64 | var re = /^(\S+)\s+(\S+\s?\S*)+\s+\((\S+)\)$/; 65 | 66 | var statuses = {}; 67 | lines.forEach(function (line) { 68 | var res = line.match(re); 69 | statuses[res[1]] = { 70 | status: res[2], 71 | provider: res[3] 72 | }; 73 | }); 74 | return statuses; 75 | } 76 | 77 | /** 78 | * parses the `vagrant --version` output 79 | * @param status 80 | */ 81 | function versionStatusParser(status) { 82 | var res = status.match(MATCHERS.versionStatus); 83 | var version = { 84 | status: null, 85 | major: null, 86 | minor: null, 87 | patch: null 88 | }; 89 | if (res) { 90 | version.status = res[1]; 91 | version.major = Number(res[2]); 92 | version.minor = Number(res[3]); 93 | version.patch = Number(res[4]); 94 | } 95 | return version; 96 | } 97 | 98 | /** 99 | * 100 | */ 101 | function globalStatusParser(data) { 102 | var lines = data.split('\n').slice(2).reduce(function (prev, curr) { 103 | if (prev.length > 0 && prev[prev.length - 1].length === 0) { 104 | return prev; 105 | } 106 | prev.push(curr.trim()); 107 | return prev; 108 | }, []); 109 | 110 | lines.pop(); 111 | if (/no active Vagrant environments/.test(lines[0])) { 112 | lines = []; 113 | } 114 | 115 | var re = /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/; 116 | lines = lines.map(function (line) { 117 | var res = line.match(re); 118 | return { 119 | id: res[1], 120 | name: res[2], 121 | provider: res[3], 122 | state: res[4], 123 | cwd: res[5] 124 | }; 125 | }); 126 | return lines; 127 | } 128 | 129 | /** 130 | * 131 | */ 132 | function sshConfigParser(out) { 133 | return out.split('\n\n') 134 | .filter(nonEmptyVagrantUpdateFilter) 135 | .map(function (out) { 136 | var config = {}; 137 | for (var key in SSH_CONFIG_MATCHERS) { 138 | var match = out.match(SSH_CONFIG_MATCHERS[key]); 139 | if (match) { 140 | config[key] = match[1]; 141 | } else { 142 | config[key] = null; 143 | if (process.env.NODE_DEBUG) { 144 | console.warn('warning ssh-config could not parse key', key); 145 | } 146 | } 147 | } 148 | return config; 149 | }); 150 | } 151 | 152 | /** 153 | * 154 | */ 155 | function boxListParser(out) { 156 | return out.split('\n') 157 | .filter(nonEmptyVagrantUpdateFilter) 158 | .filter(noBoxResponse) 159 | .map(function (out) { 160 | var box = {}; 161 | for (var key in BOX_LIST_MATCHERS) { 162 | box[key] = out.match(BOX_LIST_MATCHERS[key])[0]; 163 | } 164 | return box; 165 | }); 166 | } 167 | /** 168 | * 169 | */ 170 | function boxListOutdatedParser(out) { 171 | return out.split('\n') 172 | .filter(nonEmptyVagrantUpdateFilter) 173 | .filter(noBoxResponse) 174 | .map(function (out) { 175 | var box = {}; 176 | 177 | box.name = out.match(/[^'*\s]+(?=')/)[0]; 178 | 179 | if (out.match(/is up to date/)) { 180 | box.status = 'up to date'; 181 | box.currentVersion = out.match(/[^(]+(?=\))/)[0]; 182 | box.latestVersion = out.match(/[^(]+(?=\))/)[0]; 183 | } else if (out.match(/is outdated!/)) { 184 | box.status = 'out of date'; 185 | box.currentVersion = (out.match(/(Current: ).+(?=. L)/)[0]).split(/\s/)[1]; 186 | box.latestVersion = (out.match(/(Latest: ).+/)[0]).split(/\s/)[1]; 187 | } else { 188 | box.status = 'unknown'; 189 | box.currentVersion = null; 190 | box.latestVersion = null; 191 | } 192 | return box; 193 | }); 194 | } 195 | 196 | function noBoxResponse(line) { 197 | return !line.includes('There are no installed boxes!'); 198 | } 199 | 200 | function nonEmptyVagrantUpdateFilter(out) { 201 | return !_.isEmpty(out) && !isVagrantCheckVersionMessage(out); 202 | } 203 | 204 | function isVagrantCheckVersionMessage(line) { 205 | var isNewVersionMessage = ( 206 | /new version of Vagrant is available/.test(line) || 207 | /To upgrade visit/.test(line) 208 | ); 209 | return _.startsWith(line, '==>') && isNewVersionMessage; 210 | } 211 | 212 | /** 213 | * 214 | */ 215 | module.exports = { 216 | downloadStatusParser: downloadStatusParser, 217 | statusParser: statusParser, 218 | globalStatusParser: globalStatusParser, 219 | sshConfigParser: sshConfigParser, 220 | boxListParser: boxListParser, 221 | boxListOutdatedParser: boxListOutdatedParser, 222 | versionStatusParser: versionStatusParser 223 | }; 224 | -------------------------------------------------------------------------------- /src/provisioners.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var _ = require('lodash'); 3 | var path = require('path'); 4 | 5 | /** 6 | * Each provisioner implements .createTemplate(provisionerConfig) which returns string which is text that will be 7 | * injected into each provisioner's config in Vagrantfile 8 | */ 9 | 10 | function CommandsAdapter() { 11 | var tplFile = fs.readFileSync(path.join(__dirname, '../templates/commands.tpl')).toString(); 12 | var compiled = _.template(tplFile); 13 | this.createTemplate = function (provisionerConfig) { 14 | return compiled({ 15 | config: provisionerConfig, 16 | commands: provisionerConfig.config.commands 17 | }); 18 | }; 19 | } 20 | 21 | function NameValueAdapter() { 22 | var tplFile = fs.readFileSync(path.join(__dirname, '../templates/name-value.tpl')).toString(); 23 | var compiled = _.template(tplFile); 24 | this.createTemplate = function (provisionerConfig) { 25 | return compiled({ 26 | rootConfig: provisionerConfig 27 | }); 28 | }; 29 | } 30 | 31 | module.exports = { 32 | _adapters: {}, 33 | createTemplate: function (provisionerConfig) { 34 | /** 35 | * There are two types of provisioner adapters: commands and name-value 36 | * Assume commands if there is .config.commands array 37 | */ 38 | var provisionerAdaterType = 'name-value'; 39 | if (provisionerConfig.config && provisionerConfig.config.commands && Array.isArray(provisionerConfig.config.commands)) { 40 | provisionerAdaterType = 'commands'; 41 | } 42 | return this._get(provisionerAdaterType).createTemplate(provisionerConfig); 43 | }, 44 | _get: function (type) { 45 | if (!this._adapters[type]) { 46 | this._adapters[type] = this._createBuiltInAdapter(type); 47 | } 48 | return this._adapters[type]; 49 | }, 50 | _createBuiltInAdapter: function (type) { 51 | if (type === 'commands') { 52 | return new CommandsAdapter(); 53 | } 54 | return new NameValueAdapter(); 55 | }, 56 | removeAdapter: function (type) { 57 | if (type in this._adapters) { 58 | delete this._adapters[type]; 59 | } 60 | }, 61 | addAdapter: function (type, adapter, force) { 62 | force = force || false; 63 | if (force) { 64 | this._adapters[type] = adapter; 65 | return true; 66 | } 67 | if (!force && !!this._adapters[type]) { 68 | return false; 69 | } 70 | this._adapters[type] = adapter; 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /templates/basic.tpl: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | <% _.forEach(config.ssh, function(value, key) { %> 14 | config.ssh.<%=key%> = "<%=value%>" 15 | <% }); %> 16 | 17 | <% _.forEach(config.vm, function(value, key) { %> 18 | config.vm.<%=key%> = "<%=value%>" 19 | <% }); %> 20 | 21 | <% if(typeof config.network !== 'undefined') { %> 22 | config.vm.network "<%= config.network.type %>"<% _.forEach(config.network.detail, function(value, key) { %>, <%= key %>: <% if(typeof value === 'string') { %>"<%=value%>"<% } else { %><%=value%><% } %><% }); %> 23 | <% } %> 24 | 25 | <% if(typeof config.providers !== 'undefined') { %> 26 | <% _.forEach(config.providers, function(settings, provider) { %> 27 | config.vm.provider "<%= provider %>" do |<%= provider %>| 28 | <% _.forEach(settings, function(value, name) { %> 29 | <%= provider %>.<%= name %> = <%= value %> 30 | <% }); %> 31 | end 32 | <% }); %> 33 | <% }; %> 34 | 35 | <% _.forEach(config.provisioners, function(provisioner) { %> 36 | config.vm.provision "<%= provisioner.type %>" do |<%= provisioner.name %>| <% _.forEach(provisioner.templateLines, function(line) { %> 37 | <%= line %><% }) %> 38 | end 39 | <% }) %> 40 | end 41 | -------------------------------------------------------------------------------- /templates/commands.tpl: -------------------------------------------------------------------------------- 1 | <% _.forEach(commands, function(command) { %> 2 | <%= config.name %>.<%=command %> 3 | <% }); %> 4 | -------------------------------------------------------------------------------- /templates/name-value.tpl: -------------------------------------------------------------------------------- 1 | <% _.forEach(rootConfig.config, function(value, name) { %> 2 | <%= rootConfig.name %>.<%= name %> = <%= value %> 3 | <% }); %> 4 | -------------------------------------------------------------------------------- /test/command-test.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events').EventEmitter; 2 | 3 | var expect = require('chai').expect; 4 | var rewire = require('rewire'); 5 | 6 | var command = rewire('../src/command'); 7 | 8 | describe('test command', function () { 9 | var exSpawn; 10 | var spawnMock; 11 | 12 | before(function () { 13 | exSpawn = command.__get__('spawn'); 14 | spawnMock = new EventEmitter(); 15 | spawnMock.stdout = new EventEmitter(); 16 | spawnMock.stderr = new EventEmitter(); 17 | }); 18 | 19 | after(function () { 20 | command.__set__('spawn', exSpawn); 21 | }); 22 | 23 | it('tests command returns spawned child', function (done) { 24 | command.__set__('spawn', function () { 25 | return spawnMock; 26 | }); 27 | 28 | var child = command.runCommand('vagrant up', function (err) {}); 29 | 30 | expect(child === spawnMock); 31 | done(); 32 | }); 33 | 34 | it('test command emits error', function (done) { 35 | var errMock = new Error(); 36 | command.__set__('spawn', function () { 37 | setTimeout(function () { 38 | spawnMock.emit('error', errMock); 39 | }, 5); 40 | return spawnMock; 41 | }); 42 | 43 | command.runCommand('vagrant up', function (err) { 44 | expect(err).to.equal(errMock); 45 | done(); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/data/box-no-box-installed.txt: -------------------------------------------------------------------------------- 1 | There are no installed boxes! Use `vagrant box add` to add some. 2 | -------------------------------------------------------------------------------- /test/data/box-outdated.txt: -------------------------------------------------------------------------------- 1 | ==> vagrant: A new version of Vagrant is available: 2.1.2! 2 | ==> vagrant: To upgrade visit: https://www.vagrantup.com/downloads.html 3 | 4 | * 'ubuntu/trusty64' (v20170818.0.0) is up to date 5 | * 'my_box' wasn't added from a catalog, no version information 6 | * 'laravel/homestead' is outdated! Current: 2.2.0. Latest: 3.0.0 7 | -------------------------------------------------------------------------------- /test/data/boxes.txt: -------------------------------------------------------------------------------- 1 | ==> vagrant: A new version of Vagrant is available: 2.1.2! 2 | ==> vagrant: To upgrade visit: https://www.vagrantup.com/downloads.html 3 | 4 | my_box (virtualbox, 0) 5 | ubuntu/trusty64 (virtualbox, 20170818.0.0) 6 | -------------------------------------------------------------------------------- /test/data/global-status.txt: -------------------------------------------------------------------------------- 1 | id name provider state directory 2 | -------------------------------------------------------------------------------------------- 3 | baa72b8 default virtualbox saved /Users/edin-m/node-vagrant/edin-m/node-vagrant/example 4 | 454ace7 default virtualbox poweroff /Users/edin-m/node-vagrant/edin-m/node-vagrant/del1 5 | 6 | The above shows information about all known Vagrant environments 7 | on this machine. This data is cached and may not be completely 8 | up-to-date. To interact with any of the machines, you can go to 9 | that directory and run Vagrant, or you can use the ID directly 10 | with Vagrant commands from any directory. For example: 11 | "vagrant destroy 1a2b3c4d" 12 | -------------------------------------------------------------------------------- /test/data/integration/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | 14 | 15 | 16 | config.vm.box = "ubuntu/trusty64" 17 | 18 | 19 | 20 | config.vm.network "public_network", guest: 83, host: 85 21 | 22 | 23 | 24 | 25 | config.vm.provider "virtualbox" do |virtualbox| 26 | 27 | virtualbox.memory = 384 28 | 29 | end 30 | 31 | config.vm.provider "lxc" do |lxc| 32 | 33 | lxc.container_name = 'test' 34 | 35 | end 36 | 37 | 38 | 39 | 40 | config.vm.provision "shell" do |shell1| 41 | shell1.path = './provision.shell.sh' 42 | end 43 | 44 | config.vm.provision "ansible" do |ansible1| 45 | ansible1.playbook = 'playbook.yml' 46 | end 47 | 48 | config.vm.provision "docker" do |docker1| 49 | docker1.pull_images = 'ubuntu' 50 | end 51 | 52 | config.vm.provision "docker" do |docker2| 53 | docker2.pull_images 'ubuntu' 54 | docker2.pull_images 'ubuntu' 55 | docker2.run 'rabbitmq' 56 | docker2.run "ubuntu", cmd: "bash -l", args: "-v '/vagrant:/var/www'" 57 | docker2.run "db-1", image: "user/mysql" 58 | end 59 | 60 | config.vm.provision "file" do |file1| 61 | file1.source = './Vagrantfile' 62 | file1.destination = '~/OutputVagrantfile' 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /test/data/integration/example1.Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | 14 | config.vm.box = "ubuntu/trusty64" 15 | 16 | 17 | 18 | config.vm.network "public_network", guest: 83, host: 85 19 | 20 | 21 | 22 | 23 | config.vm.provider "virtualbox" do |virtualbox| 24 | 25 | virtualbox.memory = 384 26 | 27 | end 28 | 29 | config.vm.provider "lxc" do |lxc| 30 | 31 | lxc.container_name = 'test' 32 | 33 | end 34 | 35 | 36 | 37 | 38 | config.vm.provision "shell" do |shell| 39 | shell.path = './provision.shell.sh' 40 | end 41 | 42 | config.vm.provision "ansible" do |ansible| 43 | ansible.playbook = 'playbook.yml' 44 | end 45 | 46 | config.vm.provision "docker" do |docker| 47 | docker.pull_images = 'ubuntu' 48 | end 49 | 50 | config.vm.provision "file" do |file| 51 | file.source = './Vagrantfile' 52 | file.destination = '~/OutputVagrantfile' 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /test/data/integration/example1.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "vm": { 4 | "box": "ubuntu/trusty64" 5 | }, 6 | "network": { 7 | "type": "public_network", 8 | "detail": { 9 | "guest": 83, 10 | "host": 85 11 | } 12 | }, 13 | "providers": { 14 | "virtualbox": { 15 | "memory": 384 16 | }, 17 | "lxc": { 18 | "container_name": "'test'" 19 | } 20 | }, 21 | "provisioners": { 22 | "shell": { 23 | "path": "'./provision.shell.sh'" 24 | }, 25 | "ansible": { 26 | "playbook": "'playbook.yml'" 27 | }, 28 | "docker": { 29 | "pull_images": "'ubuntu'" 30 | }, 31 | "file": { 32 | "source": "'./Vagrantfile'", 33 | "destination": "'~/OutputVagrantfile'" 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/data/integration/example2.Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | 14 | config.vm.box = "ubuntu/trusty64" 15 | 16 | 17 | 18 | config.vm.network "public_network", guest: 83, host: 85 19 | 20 | 21 | 22 | 23 | config.vm.provider "virtualbox" do |virtualbox| 24 | 25 | virtualbox.memory = 384 26 | 27 | end 28 | 29 | config.vm.provider "lxc" do |lxc| 30 | 31 | lxc.container_name = 'test' 32 | 33 | end 34 | 35 | 36 | 37 | 38 | config.vm.provision "shell" do |shell1| 39 | shell1.path = './provision.shell.sh' 40 | end 41 | 42 | config.vm.provision "ansible" do |ansible1| 43 | ansible1.playbook = 'playbook.yml' 44 | end 45 | 46 | config.vm.provision "docker" do |docker1| 47 | docker1.pull_images = 'ubuntu' 48 | end 49 | 50 | config.vm.provision "docker" do |docker2| 51 | docker2.pull_images 'ubuntu' 52 | docker2.pull_images 'ubuntu' 53 | docker2.run 'rabbitmq' 54 | docker2.run "ubuntu", cmd: "bash -l", args: "-v '/vagrant:/var/www'" 55 | docker2.run "db-1", image: "user/mysql" 56 | end 57 | 58 | config.vm.provision "file" do |file1| 59 | file1.source = './Vagrantfile' 60 | file1.destination = '~/OutputVagrantfile' 61 | end 62 | 63 | end 64 | -------------------------------------------------------------------------------- /test/data/integration/example2.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "vm": { 4 | "box": "ubuntu/trusty64" 5 | }, 6 | "network": { 7 | "type": "public_network", 8 | "detail": { 9 | "guest": 83, 10 | "host": 85 11 | } 12 | }, 13 | "providers": { 14 | "virtualbox": { 15 | "memory": 384 16 | }, 17 | "lxc": { 18 | "container_name": "'test'" 19 | } 20 | }, 21 | "provisioners": [ 22 | { 23 | "type": "shell", 24 | "name": "shell1", 25 | "config": { 26 | "path": "'./provision.shell.sh'" 27 | } 28 | }, 29 | { 30 | "type": "ansible", 31 | "name": "ansible1", 32 | "config": { 33 | "playbook": "'playbook.yml'" 34 | } 35 | }, 36 | { 37 | "type": "docker", 38 | "name": "docker1", 39 | "config": { 40 | "pull_images": "'ubuntu'" 41 | } 42 | }, 43 | { 44 | "type": "docker", 45 | "name": "docker2", 46 | "config": { 47 | "commands": [ 48 | "pull_images 'ubuntu'", 49 | "pull_images 'ubuntu'", 50 | "run 'rabbitmq'", 51 | "run \"ubuntu\", cmd: \"bash -l\", args: \"-v '/vagrant:/var/www'\"", 52 | "run \"db-1\", image: \"user/mysql\"" 53 | ] 54 | } 55 | }, 56 | { 57 | "type": "file", 58 | "name": "file1", 59 | "config": { 60 | "source": "'./Vagrantfile'", 61 | "destination": "'~/OutputVagrantfile'" 62 | } 63 | } 64 | ] 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/data/provision.shell.sh: -------------------------------------------------------------------------------- 1 | sudo apt-get update 2 | sudo apt-get install -y git -------------------------------------------------------------------------------- /test/data/ssh-config-nokey.txt: -------------------------------------------------------------------------------- 1 | Host default 2 | HostName 127.0.0.1 3 | User vagrant 4 | Port 2222 5 | UserKnownHostsFile /dev/null 6 | StrictHostKeyChecking no 7 | PasswordAuthentication no 8 | IdentitiesOnly yes 9 | LogLevel FATAL 10 | -------------------------------------------------------------------------------- /test/data/ssh-config.txt: -------------------------------------------------------------------------------- 1 | Host default 2 | HostName 127.0.0.1 3 | User vagrant 4 | Port 2222 5 | UserKnownHostsFile /dev/null 6 | StrictHostKeyChecking no 7 | PasswordAuthentication no 8 | IdentityFile /Users/edin-m/node-vagrant/edin-m/node-vagrant/del1/.vagrant/machines/default/virtualbox/private_key 9 | IdentitiesOnly yes 10 | LogLevel FATAL 11 | -------------------------------------------------------------------------------- /test/data/status: -------------------------------------------------------------------------------- 1 | ==> vagrant: A new version of Vagrant is available: 2.1.2! 2 | ==> vagrant: To upgrade visit: https://www.vagrantup.com/downloads.html 3 | 4 | All Plugin Dependencies already installed 5 | Current machine states: 6 | 7 | my_server running (docker) 8 | rethinkDB not created (virtualbox) 9 | 10 | This environment represents multiple VMs. The VMs are all listed 11 | above with their current state. For more information about a specific 12 | VM, run `vagrant status NAME`. 13 | -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | function setupIntegrationTests() { 2 | return { 3 | describe: Number(process.env.RUN_INTEGRATION_TESTS) === 1 ? describe : describe.skip, 4 | it: Number(process.env.RUN_INTEGRATION_TESTS) === 1 ? it : it.skip 5 | }; 6 | } 7 | 8 | module.exports = { 9 | integration: setupIntegrationTests() 10 | }; 11 | -------------------------------------------------------------------------------- /test/index-test.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events').EventEmitter; 2 | var expect = require('chai').expect; 3 | var sinon = require('sinon'); 4 | var rewire = require('rewire'); 5 | 6 | var vagrant = rewire('../src/index'); 7 | 8 | /* eslint no-unused-vars: ["error", { "args": "none" }] */ 9 | /* eslint quotes: "off" */ 10 | 11 | describe('it should test node-vagrant', function () { 12 | describe('should test vagrant box commands', function () { 13 | var runFuncBeforeVagrant; 14 | 15 | before(function (done) { 16 | runFuncBeforeVagrant = vagrant._run; 17 | done(); 18 | }); 19 | 20 | it('should test box add', function (done) { 21 | vagrant._run = function (command) { 22 | expect(command).to.be.an('array'); 23 | expect(command.length).to.equal(4); 24 | expect(command[0]).to.equal('box'); 25 | expect(command[1]).to.equal('add'); 26 | expect(command[2]).to.equal('-f'); 27 | expect(command[3]).to.equal('ubuntu/trusty64'); 28 | done(); 29 | return { stdout: { on: function () { } }, stderr: { } }; 30 | }; 31 | vagrant.boxAdd('ubuntu/trusty64'); 32 | }); 33 | it('should test box add emit progress', function (done) { 34 | var dataStr = ' default: Progress: 97% (Rate: 899k/s, Estimated time remaining: 0:00:24)'; 35 | var ee = new EventEmitter; 36 | var spy = sinon.spy(); 37 | vagrant._run = function (command) { 38 | return { stdout: ee, stderr: { } }; 39 | }; 40 | vagrant.boxAdd('ubuntu/trusty64') 41 | .once('progress', spy); 42 | ee.emit('data', dataStr); 43 | expect(spy.calledOnce).to.equal(true); 44 | expect(spy.getCall(0).args).to.deep.equal(['default', '97', '899k/s', '0:00:24']); 45 | done(); 46 | }); 47 | it('should test box list', function (done) { 48 | vagrant._run = function (command) { 49 | expect(command).to.be.an('array'); 50 | expect(command.length).to.equal(2); 51 | expect(command[0]).to.equal('box'); 52 | expect(command[1]).to.equal('list'); 53 | done(); 54 | }; 55 | vagrant.boxList(); 56 | }); 57 | it('should test box outdated', function (done) { 58 | vagrant._run = function (command) { 59 | expect(command).to.be.an('array'); 60 | expect(command.length).to.equal(3); 61 | expect(command[0]).to.equal('box'); 62 | expect(command[1]).to.equal('outdated'); 63 | expect(command[2]).to.equal('--global'); 64 | done(); 65 | }; 66 | vagrant.boxOutdated(); 67 | }); 68 | it('should test box prune', function (done) { 69 | vagrant._run = function (command) { 70 | expect(command).to.be.an('array'); 71 | expect(command.length).to.equal(3); 72 | expect(command[0]).to.equal('box'); 73 | expect(command[1]).to.equal('prune'); 74 | expect(command[2]).to.equal('-f'); 75 | done(); 76 | }; 77 | vagrant.boxPrune(); 78 | }); 79 | it('should test box remove', function (done) { 80 | vagrant._run = function (command) { 81 | expect(command).to.be.an('array'); 82 | expect(command.length).to.equal(4); 83 | expect(command[0]).to.equal('box'); 84 | expect(command[1]).to.equal('remove'); 85 | expect(command[2]).to.equal('-f'); 86 | expect(command[3]).to.equal('ubuntu/trusty64'); 87 | done(); 88 | }; 89 | vagrant.boxRemove('ubuntu/trusty64'); 90 | }); 91 | it('should test box update', function (done) { 92 | vagrant._run = function (command) { 93 | expect(command).to.be.an('array'); 94 | expect(command.length).to.equal(6); 95 | expect(command[0]).to.equal('box'); 96 | expect(command[1]).to.equal('update'); 97 | expect(command[2]).to.equal('--box'); 98 | expect(command[3]).to.equal('ubuntu/trusty64'); 99 | expect(command[4]).to.equal('--provider'); 100 | expect(command[5]).to.equal('virtualbox'); 101 | done(); 102 | return { stdout: { on: function () { } }, stderr: { } }; 103 | }; 104 | vagrant.boxUpdate('ubuntu/trusty64', 'virtualbox'); 105 | }); 106 | it('should test box list calling parser', function (done) { 107 | var spy = sinon.spy(); 108 | var revert = vagrant.__set__('parsers', { boxListParser: spy }); 109 | vagrant._run = function (command, cb) { 110 | cb(); 111 | expect(spy.calledOnce).to.equal(true); 112 | revert(); 113 | done(); 114 | }; 115 | 116 | vagrant.boxList(function () {}); 117 | }); 118 | it('should test box outdated calling parser', function (done) { 119 | var spy = sinon.spy(); 120 | var revert = vagrant.__set__('parsers', { boxListOutdatedParser: spy }); 121 | vagrant._run = function (command, cb) { 122 | cb(); 123 | expect(spy.calledOnce).to.equal(true); 124 | revert(); 125 | done(); 126 | }; 127 | 128 | vagrant.boxOutdated(function () {}); 129 | }); 130 | it('should test box update emit progress', function (done) { 131 | var dataStr = ' default: Progress: 97% (Rate: 899k/s, Estimated time remaining: 0:00:24)'; 132 | var ee = new EventEmitter; 133 | var spy = sinon.spy(); 134 | vagrant._run = function (command) { 135 | return { stdout: ee, stderr: { } }; 136 | }; 137 | vagrant.boxUpdate('ubuntu/trusty64', 'virtualbox') 138 | .once('progress', spy); 139 | ee.emit('data', dataStr); 140 | expect(spy.calledOnce).to.equal(true); 141 | expect(spy.getCall(0).args).to.deep.equal(['default', '97', '899k/s', '0:00:24']); 142 | done(); 143 | }); 144 | 145 | it('should test box update without the provider', function (done) { 146 | vagrant._run = function (command) { 147 | expect(command).to.be.an('array'); 148 | expect(command.length).to.equal(4); 149 | expect(command[0]).to.equal('box'); 150 | expect(command[1]).to.equal('update'); 151 | expect(command[2]).to.equal('--box'); 152 | expect(command[3]).to.equal('ubuntu/trusty64'); 153 | done(); 154 | return { stdout: { on: function () { } }, stderr: { } }; 155 | }; 156 | vagrant.boxUpdate('ubuntu/trusty64', null); 157 | }); 158 | 159 | after(function (done) { 160 | vagrant._run = runFuncBeforeVagrant; 161 | done(); 162 | }); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /test/integration-test.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var expect = require('chai').expect; 4 | 5 | var vagrant = require('../index'); 6 | var helpers = require('./helpers'); 7 | var describe = helpers.integration.describe; 8 | var it = helpers.integration.it; 9 | 10 | /* eslint no-unused-vars: ["error", { "args": "none" }] */ 11 | /* eslint quotes: "off" */ 12 | 13 | describe('it should test node-vagrant', function () { 14 | var machine; 15 | var workingDir = path.join(__dirname, 'data/integration'); 16 | var unlinkOutputFiles = true; 17 | 18 | before(function (done) { 19 | if (!fs.existsSync(workingDir)) { 20 | fs.mkdirSync(workingDir); 21 | } 22 | machine = vagrant.create({ cwd: workingDir }); 23 | done(); 24 | }); 25 | 26 | it('should test creation of example1 Vagrantfile', function (done) { 27 | this.timeout(20000); 28 | var config = require(path.join(workingDir, './example1.config.json')); 29 | machine.init('ubuntu/trusty64', config, function (err, out) { 30 | expect(err).to.not.exist; 31 | 32 | machine.isInitialized = true; 33 | var origLoc = path.join(workingDir, 'Vagrantfile'); 34 | var exampleLoc = path.join(workingDir, 'example1.Vagrantfile'); 35 | 36 | var Vagrantfile = fs.readFileSync(origLoc).toString(); 37 | var exampleVagrantfile = fs.readFileSync(exampleLoc).toString(); 38 | 39 | // for previewing purposes 40 | fs.writeFileSync(path.join(workingDir, 'out.example1.Vagrantfile'), Vagrantfile); 41 | 42 | expect(Vagrantfile.replace(/[\n\r]/gm, '')).to.equal(exampleVagrantfile.replace(/[\n\r]/gm, '')); 43 | fs.unlinkSync(origLoc); 44 | done(); 45 | }); 46 | }); 47 | 48 | it('should test creation of example2 Vagranfile', function (done) { 49 | this.timeout(20000); 50 | var config = require(path.join(workingDir, './example2.config.json')); 51 | machine.init('ubuntu/trusty64', config, function (err, out) { 52 | expect(err).to.not.exist; 53 | 54 | machine.isInitialized = true; 55 | var origLoc = path.join(workingDir, 'Vagrantfile'); 56 | var exampleLoc = path.join(workingDir, 'example2.Vagrantfile'); 57 | 58 | var Vagrantfile = fs.readFileSync(origLoc).toString(); 59 | var exampleVagrantfile = fs.readFileSync(exampleLoc).toString(); 60 | 61 | // for previewing purposes 62 | fs.writeFileSync(path.join(workingDir, 'out.example2.Vagrantfile'), Vagrantfile); 63 | 64 | expect(Vagrantfile.replace(/[\n\r]/gm, '')).to.equal(exampleVagrantfile.replace(/[\n\r]/gm, '')); 65 | // fs.unlinkSync(origLoc); 66 | done(); 67 | }); 68 | }); 69 | 70 | it('should destroy machine', function (done) { 71 | this.timeout(10000); 72 | machine.destroy(function (err, res) { 73 | expect(err).to.not.exist; 74 | done(); 75 | }); 76 | }); 77 | 78 | after(function (done) { 79 | this.timeout(20000); 80 | var filesToUnlink = [ 81 | path.join(workingDir, 'out.example1.Vagrantfile'), 82 | path.join(workingDir, './out.example2.Vagrantfile') 83 | ]; 84 | unlinkOutputFiles && filesToUnlink.forEach(function (filename) { 85 | if (fs.existsSync(filename)) { 86 | // comment out this line to be able to see output example Vagrantfiles 87 | fs.unlinkSync(filename); 88 | } 89 | }); 90 | done(); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /test/machine-test.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events').EventEmitter; 2 | 3 | var rewire = require('rewire'); 4 | var expect = require('chai').expect; 5 | var sinon = require('sinon'); 6 | 7 | var Machine = rewire('../src/machine'); 8 | 9 | /* eslint no-unused-vars: ["error", { "args": "none" }] */ 10 | /* eslint quotes: "off" */ 11 | 12 | describe('it should test Machine class', function () { 13 | var machine; 14 | var commandMock = Machine.__get__('Command'); 15 | 16 | before(function (done) { 17 | machine = new Machine({ cwd: __dirname }); 18 | done(); 19 | }); 20 | 21 | beforeEach(function (done) { 22 | commandMock = Machine.__get__('Command'); 23 | done(); 24 | }); 25 | 26 | afterEach(function (done) { 27 | Machine.__set__('Command', commandMock); 28 | done(); 29 | }); 30 | 31 | describe('should test machine commands', function () { 32 | // mock _mainRun as to call a callback within tests 33 | var runFuncBefore; 34 | beforeEach(function (done) { 35 | runFuncBefore = machine._run; 36 | done(); 37 | }); 38 | afterEach(function (done) { 39 | machine._run = runFuncBefore; 40 | done(); 41 | }); 42 | it('should test machine init', function (done) { 43 | machine._run = function (command) { 44 | expect(command).to.be.an('array'); 45 | expect(command.length).to.equal(3); 46 | expect(command[0]).to.equal('init'); 47 | expect(command[1]).to.equal('ubuntu/trusty64'); 48 | expect(command[2]).to.equal('-f'); 49 | done(); 50 | }; 51 | machine.init('ubuntu/trusty64', { }, function () { }); 52 | }); 53 | it('should test machine init without config', function (done) { 54 | var oldChangeVagrantfile = machine._changeVagrantfile; 55 | machine._changeVagrantfile = function (config) { 56 | machine._changeVagrantfile = oldChangeVagrantfile; 57 | expect(config.config.vm.box).to.equal('ubuntu/trusty64'); 58 | done(); 59 | }; 60 | machine._run = function (command, cb) { 61 | cb(null); 62 | }; 63 | machine.init('ubuntu/trusty64'); 64 | }); 65 | it('should test machine up', function (done) { 66 | machine._run = function (command) { 67 | expect(command).to.be.an('array'); 68 | expect(command.length).to.equal(1); 69 | expect(command[0]).to.equal('up'); 70 | done(); 71 | return { stdout: { on: function () { } }, stderr: { } }; 72 | }; 73 | machine.up(); 74 | }); 75 | it('should test machine up emit progress', function (done) { 76 | var dataStr = ' default: Progress: 97% (Rate: 899k/s, Estimated time remaining: 0:00:24)'; 77 | var ee = new EventEmitter; 78 | var spy = sinon.spy(); 79 | machine._run = function (command) { 80 | return { stdout: ee, stderr: { } }; 81 | }; 82 | machine.once('up-progress', spy); 83 | machine.up(); 84 | ee.emit('data', dataStr); 85 | expect(spy.calledOnce).to.equal(true); 86 | expect(spy.getCall(0).args[0]).to.equal(dataStr); 87 | done(); 88 | }); 89 | it('should test machine up emit up-progress', function (done) { 90 | var dataStr = ' default: Progress: 97% (Rate: 899k/s, Estimated time remaining: 0:00:24)'; 91 | var ee = new EventEmitter; 92 | var spy = sinon.spy(); 93 | machine._run = function (command) { 94 | return { stdout: ee, stderr: { } }; 95 | }; 96 | machine.once('progress', spy); 97 | machine.up(); 98 | ee.emit('data', dataStr); 99 | expect(spy.calledOnce).to.equal(true); 100 | expect(spy.getCall(0).args).to.deep.equal(['default', '97', '899k/s', '0:00:24']); 101 | done(); 102 | }); 103 | it('should test machine status', function (done) { 104 | machine._run = function (command) { 105 | expect(command).to.be.an('array'); 106 | expect(command.length).to.equal(1); 107 | expect(command[0]).to.equal('status'); 108 | done(); 109 | }; 110 | machine.status(); 111 | }); 112 | it('should test machine ssh config', function (done) { 113 | machine._run = function (command) { 114 | expect(command).to.be.an('array'); 115 | expect(command.length).to.equal(1); 116 | expect(command[0]).to.equal('ssh-config'); 117 | done(); 118 | }; 119 | machine.sshConfig(); 120 | }); 121 | it('should test machine ssh command', function (done) { 122 | machine._run = function (command) { 123 | expect(command).to.be.an('array'); 124 | expect(command.length).to.equal(3); 125 | expect(command[0]).to.equal('ssh'); 126 | done(); 127 | }; 128 | machine.sshCommand('echo test'); 129 | }); 130 | it('should test machine ssh command emit stdout', function (done) { 131 | var ee = new EventEmitter; 132 | var spy = sinon.spy(); 133 | machine._run = function (command) { 134 | return { stdout: ee, stderr: new EventEmitter }; 135 | }; 136 | machine.once('ssh-out', spy); 137 | machine.sshCommand('echo test'); 138 | ee.emit('data', 'test'); 139 | expect(spy.calledOnce).to.equal(true); 140 | expect(spy.getCall(0).args[0]).to.equal('test'); 141 | done(); 142 | }); 143 | it('should test machine ssh command emit stderr', function (done) { 144 | var ee = new EventEmitter; 145 | var spy = sinon.spy(); 146 | machine._run = function (command) { 147 | return { stdout: new EventEmitter, stderr: ee }; 148 | }; 149 | machine.once('ssh-err', spy); 150 | machine.sshCommand('1>&2 echo test'); 151 | ee.emit('data', 'test'); 152 | expect(spy.calledOnce).to.equal(true); 153 | expect(spy.getCall(0).args[0]).to.equal('test'); 154 | done(); 155 | }); 156 | it('should test machine suspend', function (done) { 157 | machine._run = function (command) { 158 | expect(command).to.be.an('array'); 159 | expect(command.length).to.equal(1); 160 | expect(command[0]).to.equal('suspend'); 161 | done(); 162 | }; 163 | machine.suspend(); 164 | }); 165 | it('should test machine resume', function (done) { 166 | machine._run = function (command) { 167 | expect(command).to.be.an('array'); 168 | expect(command.length).to.equal(1); 169 | expect(command[0]).to.equal('resume'); 170 | done(); 171 | }; 172 | machine.resume(); 173 | }); 174 | it('should test machine halt', function (done) { 175 | machine._run = function (command) { 176 | expect(command).to.be.an('array'); 177 | expect(command.length).to.equal(2); 178 | expect(command[0]).to.equal('halt'); 179 | expect(command[1]).to.equal('-f'); 180 | done(); 181 | }; 182 | machine.halt(); 183 | }); 184 | it('should test machine destroy', function (done) { 185 | machine._run = function (command) { 186 | expect(command).to.be.an('array'); 187 | expect(command.length).to.equal(2); 188 | expect(command[0]).to.equal('destroy'); 189 | expect(command[1]).to.equal('-f'); 190 | done(); 191 | }; 192 | machine.destroy(); 193 | }); 194 | 195 | describe('should test snapshots', function () { 196 | it('should test snapshots() push()', function (done) { 197 | machine._run = function (command, cb) { 198 | expect(command).to.be.an('array'); 199 | expect(command.length).to.equal(2); 200 | expect(command[0]).to.equal('snapshot'); 201 | expect(command[1]).to.equal('push'); 202 | cb(); 203 | }; 204 | machine.snapshots().push(done); 205 | }); 206 | it('should test snapshots() pop()', function (done) { 207 | machine._run = function (command, cb) { 208 | expect(command).to.be.an('array'); 209 | expect(command.length).to.equal(2); 210 | expect(command[0]).to.equal('snapshot'); 211 | expect(command[1]).to.equal('pop'); 212 | cb(); 213 | }; 214 | machine.snapshots().pop(done); 215 | }); 216 | it('should test snapshots() save()', function (done) { 217 | machine._run = function (command) { 218 | expect(command).to.be.an('array'); 219 | expect(command.length).to.equal(1); 220 | expect(command[0]).to.equal('snapshot save'); 221 | done(); 222 | }; 223 | machine.snapshots().save(); 224 | }); 225 | it('should test snapshots() delete()', function (done) { 226 | machine._run = function (command) { 227 | expect(command).to.be.an('array'); 228 | expect(command.length).to.equal(1); 229 | expect(command[0]).to.equal('snapshot delete'); 230 | done(); 231 | }; 232 | machine.snapshots().delete(); 233 | }); 234 | it('should test snapshots() restore()', function (done) { 235 | machine._run = function (command) { 236 | expect(command).to.be.an('array'); 237 | expect(command.length).to.equal(1); 238 | expect(command[0]).to.equal('snapshot restore'); 239 | done(); 240 | }; 241 | machine.snapshots().restore(); 242 | }); 243 | it('should test snapshots() list()', function (done) { 244 | machine._run = function (command) { 245 | expect(command).to.be.an('array'); 246 | expect(command.length).to.equal(2); 247 | expect(command[0]).to.equal('snapshot'); 248 | expect(command[1]).to.equal('list'); 249 | done(); 250 | }; 251 | machine.snapshots().list(); 252 | }); 253 | }); 254 | 255 | it('should test box repackge', function (done) { 256 | machine._run = function (command) { 257 | expect(command).to.be.an('array'); 258 | expect(command.length).to.equal(5); 259 | expect(command[0]).to.equal('box'); 260 | expect(command[1]).to.equal('repackage'); 261 | expect(command[2]).to.equal('ubuntu/trusty64'); 262 | expect(command[3]).to.equal('virtualbox'); 263 | expect(command[4]).to.equal('someNewVersion'); 264 | done(); 265 | return { stdout: { on: function () { } }, stderr: { } }; 266 | }; 267 | machine.boxRepackage('ubuntu/trusty64', 'virtualbox', 'someNewVersion'); 268 | }); 269 | it('should prepare provisioners from object config to array config', function (done) { 270 | var config = { 271 | config: { 272 | provisioners: { 273 | shell: { 274 | path: "'./provision.shell.sh'" 275 | }, 276 | ansible: { 277 | playbook: "'playbook.yml'" 278 | }, 279 | docker: { 280 | pull_images: "'ubuntu'" 281 | }, 282 | file: { 283 | source: "'./Vagrantfile'", 284 | destination: "'~/OutputVagrantfile'" 285 | } 286 | } 287 | } 288 | }; 289 | var exprovisioners = config.config.provisioners; 290 | machine._prepareProvisioners(config.config); 291 | expect(config.config.provisioners).to.be.an('array'); 292 | expect(config.config.provisioners.length).to.equal(4); 293 | config.config.provisioners.forEach(function (provisioner, index) { 294 | expect(provisioner).to.be.an('object'); 295 | var origKey = Object.keys(exprovisioners)[index]; 296 | expect(provisioner.name).to.equal(origKey); 297 | var orig = exprovisioners[origKey]; 298 | for (var key in provisioner.config) { 299 | expect(provisioner.config[key]).to.equal(orig[key]); 300 | } 301 | }); 302 | done(); 303 | }); 304 | 305 | it('should emit stdout', function (done) { 306 | var ee = new EventEmitter(); 307 | var buf = Buffer.from('output'); 308 | Machine.__set__('Command', { 309 | runCommand: function (_, opts, cb) { 310 | cb(); 311 | setTimeout(function () { 312 | ee.emit('data', buf); 313 | }, 15); 314 | return { stdout: ee }; 315 | } 316 | }); 317 | 318 | machine.on('stdout', function (data) { 319 | expect(data).to.equal(buf); 320 | done(); 321 | }); 322 | machine._run('any command', function () {}); 323 | }); 324 | 325 | it('should emit stderr', function (done) { 326 | var ee = new EventEmitter(); 327 | var buf = Buffer.from('output'); 328 | Machine.__set__('Command', { 329 | runCommand: function (_, opts, cb) { 330 | cb(); 331 | setTimeout(function () { 332 | ee.emit('data', buf); 333 | }, 15); 334 | return { stderr: ee }; 335 | } 336 | }); 337 | 338 | machine.on('stderr', function (data) { 339 | expect(data).to.equal(buf); 340 | done(); 341 | }); 342 | 343 | machine._run(['any command'], function () {}); 344 | }); 345 | }); 346 | }); 347 | -------------------------------------------------------------------------------- /test/parsers-test.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var expect = require('chai').expect; 3 | 4 | var parsers = require('../src/parsers'); 5 | 6 | describe('test parsers', function () { 7 | it('should test download parser', function () { 8 | var downloadProgressStr = ' default: Progress: 19% (Rate: 619k/s, Estimated time remaining: 0:11:38)'; 9 | var result = parsers.downloadStatusParser(downloadProgressStr); 10 | expect(result).to.deep.equal({ 11 | machine: 'default', 12 | progress: '19', 13 | rate: '619k/s', 14 | remaining: '0:11:38' 15 | }); 16 | }); 17 | it('should test download parser - error', function () { 18 | var downloadProgressStr = ' default: Progress: 19% (Rate: 619k/s,Estimated time remaining: 0:11:38)'; 19 | var result = parsers.downloadStatusParser(downloadProgressStr); 20 | expect(result).to.equal(null); 21 | }); 22 | describe('Vagrant status parsing', function () { 23 | it('should parse all status information', function () { 24 | var exStats = fs.readFileSync(__dirname + '/data/status').toString(); 25 | var machStats = parsers.statusParser(exStats); 26 | expect(Object.keys(machStats).length).to.equal(2); 27 | expect(machStats['my_server'].status).to.equal('running'); 28 | expect(machStats['my_server'].provider).to.equal('docker'); 29 | expect(machStats['rethinkDB'].status).to.equal('not created'); 30 | expect(machStats['rethinkDB'].provider).to.equal('virtualbox'); 31 | }); 32 | }); 33 | it('should test global status parser', function () { 34 | var data = fs.readFileSync(__dirname + '/data/global-status.txt').toString(); 35 | var res = parsers.globalStatusParser(data); 36 | expect(res).to.deep.equal([{ 37 | id: 'baa72b8', 38 | name: 'default', 39 | provider: 'virtualbox', 40 | state: 'saved', 41 | cwd: '/Users/edin-m/node-vagrant/edin-m/node-vagrant/example' 42 | }, { 43 | id: '454ace7', 44 | name: 'default', 45 | provider: 'virtualbox', 46 | state: 'poweroff', 47 | cwd: '/Users/edin-m/node-vagrant/edin-m/node-vagrant/del1' 48 | }]); 49 | }); 50 | it('should test sshConfig parser', function () { 51 | var data = fs.readFileSync(__dirname + '/data/ssh-config.txt').toString(); 52 | var res = parsers.sshConfigParser(data); 53 | expect(res).to.deep.equal([{ 54 | host: 'default', 55 | port: '2222', 56 | hostname: '127.0.0.1', 57 | user: 'vagrant', 58 | private_key: '/Users/edin-m/node-vagrant/edin-m/node-vagrant/del1/.vagrant/machines/default/virtualbox/private_key' 59 | }]); 60 | }); 61 | it('should test sshConfig parser', function () { 62 | var data = fs.readFileSync(__dirname + '/data/ssh-config-nokey.txt').toString(); 63 | var res = parsers.sshConfigParser(data); 64 | expect(res).to.deep.equal([{ 65 | host: 'default', 66 | port: '2222', 67 | hostname: '127.0.0.1', 68 | user: 'vagrant', 69 | private_key: null 70 | }]); 71 | }); 72 | it('should test box list parser', function () { 73 | var data = fs.readFileSync(__dirname + '/data/boxes.txt').toString(); 74 | var res = parsers.boxListParser(data); 75 | expect(res).to.deep.equal([{ 76 | name: 'my_box', 77 | provider: 'virtualbox', 78 | version: '0', 79 | }, { 80 | name: 'ubuntu/trusty64', 81 | provider: 'virtualbox', 82 | version: '20170818.0.0', 83 | }]); 84 | }); 85 | it('should test box list parser - no box installed', function () { 86 | var data = fs.readFileSync(__dirname + '/data/box-no-box-installed.txt').toString(); 87 | var res = parsers.boxListParser(data); 88 | expect(res).to.deep.equal([]); 89 | }); 90 | it('should test box outdated parser', function () { 91 | var data = fs.readFileSync(__dirname + '/data/box-outdated.txt').toString(); 92 | var res = parsers.boxListOutdatedParser(data); 93 | expect(res).to.deep.equal([{ 94 | name: 'ubuntu/trusty64', 95 | status: 'up to date', 96 | currentVersion: 'v20170818.0.0', 97 | latestVersion: 'v20170818.0.0' 98 | }, { 99 | name: 'my_box', 100 | status: 'unknown', 101 | currentVersion: null, 102 | latestVersion: null 103 | }, { 104 | name: 'laravel/homestead', 105 | status: 'out of date', 106 | currentVersion: '2.2.0', 107 | latestVersion: '3.0.0' 108 | }]); 109 | }); 110 | it('should test version status parser', function () { 111 | var versionStatus = 'Vagrant 2.0.3\n'; 112 | var version = parsers.versionStatusParser(versionStatus); 113 | expect(version.status).to.equal('2.0.3'); 114 | expect(version.major).to.equal(2); 115 | expect(version.minor).to.equal(0); 116 | expect(version.patch).to.equal(3); 117 | }); 118 | }); 119 | -------------------------------------------------------------------------------- /test/provisioners-test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var provisionerAdapters = require('../src/provisioners'); 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var _ = require('lodash'); 6 | 7 | /** 8 | * Split on newlines, trim lines and filter out empty lines 9 | */ 10 | function trimAndRemoveEmpty(result) { 11 | return result.split(/\n|\r/).map(function (item) { 12 | return item.trim(); 13 | }).filter(function (item) { 14 | return item.length > 0; 15 | }); 16 | } 17 | 18 | describe('Test provisioner adapters', function () { 19 | it('Generic name value adapter', function (done) { 20 | var provisionerConfig = { 21 | name: 'wtf', 22 | config: { 23 | name: 'value', 24 | name2: 'value2' 25 | } 26 | }; 27 | var result = provisionerAdapters.createTemplate(provisionerConfig); 28 | var lines = trimAndRemoveEmpty(result); 29 | expect(lines.length).to.equal(2); 30 | done(); 31 | }); 32 | it('Commands provisioner adapter', function (done) { 33 | var provisionerConfig = { 34 | name: 'docker1', 35 | config: { 36 | commands: [ 37 | 'pull_images "ubuntu"', 38 | 'pull_images "debian"', 39 | 'run "rabbitmq"' 40 | ] 41 | } 42 | }; 43 | var result = provisionerAdapters.createTemplate(provisionerConfig); 44 | var lines = trimAndRemoveEmpty(result); 45 | for (var i = 0; i < provisionerConfig.config.commands.length; i++) { 46 | var reg = new RegExp(provisionerConfig.config.commands[i].replace('[', '\\[').replace(']', '\\]')); 47 | expect(lines[i]).to.match(reg); 48 | } 49 | done(); 50 | }); 51 | it('Docker adapter commands', function (done) { 52 | var provisionerConfig = { 53 | name: 'docker1', 54 | type: 'docker', 55 | config: { 56 | commands: [ 57 | 'pull_images "ubuntu"', 58 | 'pull_images "ubuntu"', 59 | 'run "rabbitmq"', 60 | 'run "ubuntu", cmd: "bash -l", args: "-v \'/vagrant:/var/www\'"', 61 | 'run "db-1", image: "user/mysql"', 62 | 'images: ["ubuntu", "gentoo"]' 63 | ] 64 | } 65 | }; 66 | var result = provisionerAdapters.createTemplate(provisionerConfig); 67 | var lines = trimAndRemoveEmpty(result); 68 | for (var i = 0; i < provisionerConfig.config.commands.length; i++) { 69 | var reg = new RegExp(provisionerConfig.config.commands[i].replace('[', '\\[').replace(']', '\\]')); 70 | expect(lines[i]).to.match(reg); 71 | } 72 | done(); 73 | }); 74 | it('Registering custom adapter', function (done) { 75 | /** 76 | * Custom adapter must implement createTemplate() which receives provisionerConfig 77 | */ 78 | function CustomAdapter() { 79 | var tplFile = fs.readFileSync(path.join(__dirname, '../templates/commands.tpl')).toString(); 80 | var compiled = _.template(tplFile); 81 | this.createTemplate = function (provisionerConfig) { 82 | return compiled({ 83 | provisioner: provisionerConfig, 84 | settings: provisionerConfig.config 85 | }); 86 | }; 87 | } 88 | provisionerAdapters.addAdapter('customAdapter', new CustomAdapter()); 89 | provisionerAdapters.removeAdapter('customAdapter'); 90 | var provisionerConfig = { 91 | name: 'custom1', 92 | type: 'customAdapter', 93 | config: { 94 | commands: [ 95 | 'pull_images "ubuntu"' 96 | ] 97 | } 98 | }; 99 | var result = provisionerAdapters.createTemplate(provisionerConfig); 100 | var lines = trimAndRemoveEmpty(result); 101 | expect(lines[0]).to.match(new RegExp(provisionerConfig.config.commands[0])); 102 | done(); 103 | }); 104 | }); 105 | --------------------------------------------------------------------------------