1 |
|
2 | 'use strict';
|
3 |
|
4 | var async = require('async');
|
5 | var util = require('util');
|
6 | var read = require('read');
|
7 | var _ = require('underscore');
|
8 | var Table = require('cli-table');
|
9 | var defaults = require('./defaults');
|
10 |
|
11 | var TableFormat = {
|
12 | chars: { 'top': '' , 'top-mid': '' , 'top-left': '' , 'top-right': ''
|
13 | , 'bottom': '' , 'bottom-mid': '' , 'bottom-left': '' , 'bottom-right': ''
|
14 | , 'left': '' , 'left-mid': '' , 'mid': '' , 'mid-mid': ''
|
15 | , 'right': '' , 'right-mid': '' , 'middle': ' ' },
|
16 | style: { 'padding-left': 0, 'padding-right': 0 }
|
17 | };
|
18 | module.exports.TableFormat = TableFormat;
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | module.exports.getopts = function(argv, start, descriptor) {
|
26 | var opts = {};
|
27 | for (var i = start; i < argv.length; i++) {
|
28 | var longArg = /^--(.+)/.exec(argv[i]);
|
29 | if (longArg) {
|
30 | var longArgName = longArg[1];
|
31 | var ld = descriptor[longArgName];
|
32 | if (ld) {
|
33 | if (ld.toggle) {
|
34 | opts[longArgName] = true;
|
35 | } else if (i < (argv.length - 1)) {
|
36 | i++;
|
37 | opts[longArgName] = argv[i];
|
38 |
|
39 | if (ld.type === 'int') {
|
40 | opts[longArgName] = parseInt(opts[longArgName], 10);
|
41 | }
|
42 |
|
43 |
|
44 | if(ld.prompt == false){
|
45 | opts.prompt = true;
|
46 | }
|
47 | } else {
|
48 | badArg(argv[i]);
|
49 | }
|
50 | }
|
51 |
|
52 | }
|
53 | else {
|
54 | var shortArg = /^-([A-Za-z])/.exec(argv[i]);
|
55 | if (shortArg) {
|
56 | var shortArgName = shortArg[1];
|
57 | var longName = undefined;
|
58 | var des;
|
59 | for (var sd in descriptor) {
|
60 | des = descriptor[sd];
|
61 | if (des.shortOption === shortArgName) {
|
62 | longName = sd;
|
63 | break;
|
64 | }
|
65 | }
|
66 |
|
67 | if (longName) {
|
68 | if (des.toggle) {
|
69 | opts[longName] = true;
|
70 | } else if (i < (argv.length - 1)) {
|
71 | i++;
|
72 | if (des.type === 'int') {
|
73 | argv[i] = parseInt(argv[i], 10);
|
74 | }
|
75 |
|
76 |
|
77 | if (des.multiple) {
|
78 | if (!opts[longName]) {
|
79 | opts[longName] = [];
|
80 | }
|
81 | opts[longName].push(argv[i]);
|
82 | } else {
|
83 | opts[longName] = argv[i];
|
84 |
|
85 |
|
86 | if(des.prompt == false){
|
87 | opts.prompt = true;
|
88 | }
|
89 | }
|
90 | } else {
|
91 | badArg(argv[i]);
|
92 | }
|
93 | } else {
|
94 | badArg(argv[i])
|
95 | }
|
96 |
|
97 | } else {
|
98 | badArg(argv[i]);
|
99 | }
|
100 | }
|
101 | }
|
102 | return opts;
|
103 | };
|
104 |
|
105 | function badArg(arg) {
|
106 | throw new Error(util.format('Unknown argument %s', arg));
|
107 | }
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | module.exports.validate = function(opts, descriptor, cb) {
|
117 | defaults.defaultOptions(opts);
|
118 | async.eachSeries(Object.getOwnPropertyNames(descriptor), function(item, done) {
|
119 | checkProperty(opts, descriptor, item, done);
|
120 | }, function(err) {
|
121 | cb(err, opts);
|
122 | });
|
123 | };
|
124 |
|
125 | function checkProperty(opts, descriptor, propName, done) {
|
126 | var desc = descriptor[propName];
|
127 | if (desc === null || desc === undefined) {
|
128 | done(new Error(util.format('Invalid property %s', propName)));
|
129 | return;
|
130 | }
|
131 | if (desc.required && !opts[propName] && (!opts.prompt && desc.prompt)) {
|
132 | if (opts.interactive) {
|
133 | var pn = (desc.name ? desc.name : propName);
|
134 | prompt(pn, desc.secure, function(err, val) {
|
135 | if (err) {
|
136 | done(err);
|
137 | } else {
|
138 | if (desc.secure === true) {
|
139 | opts[propName] = new SecureValue(val);
|
140 | } else {
|
141 | opts[propName] = val;
|
142 | }
|
143 | done();
|
144 | }
|
145 | });
|
146 | } else {
|
147 | done(new Error(util.format('Missing required option "%s"', propName)));
|
148 | }
|
149 | } else {
|
150 | if (opts[propName] && (desc.secure === true)) {
|
151 | makeSecure(opts, propName);
|
152 | }
|
153 | done();
|
154 | }
|
155 | }
|
156 |
|
157 | function prompt(name, secure, cb) {
|
158 | var opts = {
|
159 | prompt: name + ':'
|
160 | };
|
161 | if (secure) {
|
162 | opts.silent = true;
|
163 | opts.replace = '*';
|
164 | }
|
165 |
|
166 | read(opts, cb);
|
167 | }
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | module.exports.validateSync = function(opts, descriptor) {
|
174 | _.each(Object.getOwnPropertyNames(descriptor), function(item) {
|
175 | checkPropertySync(opts, descriptor, item);
|
176 | });
|
177 | };
|
178 |
|
179 | function checkPropertySync(opts, descriptor, propName) {
|
180 | var desc = descriptor[propName];
|
181 | if (desc === null || desc === undefined) {
|
182 | var err = new Error(util.format('Invalid property %s', propName));
|
183 | console.error(err);
|
184 | throw err;
|
185 | }
|
186 | if (desc.required && !opts[propName] && (!opts.prompt && desc.prompt)) {
|
187 | var err = new Error(util.format('Missing required option "%s"', propName));
|
188 | console.error(err);
|
189 | throw err;
|
190 | } else {
|
191 | if (opts[propName] && (desc.secure === true)) {
|
192 | makeSecure(opts, propName);
|
193 | }
|
194 | }
|
195 | }
|
196 |
|
197 | function makeSecure(opts, propName) {
|
198 | if (opts[propName] && (!(opts[propName] instanceof SecureValue))) {
|
199 | opts[propName] = new SecureValue(opts[propName]);
|
200 | }
|
201 | }
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | module.exports.getHelp = function(descriptor) {
|
207 | var tab = new Table(TableFormat);
|
208 |
|
209 | _.each(_.sortBy(_.pairs(descriptor)), function(d) {
|
210 | tab.push([d[0],
|
211 | (d[1].shortOption ? '-' + d[1].shortOption : ''),
|
212 | ((d[1].required && !d[1].prompt) ? '(required)': '(optional)')]);
|
213 | });
|
214 |
|
215 | return tab.toString();
|
216 | };
|
217 |
|
218 |
|
219 |
|
220 |
|
221 | function SecureValue(val) {
|
222 | if (!(this instanceof SecureValue)) {
|
223 | return new SecureValue(val);
|
224 | }
|
225 | Object.defineProperty(this, 'value', {
|
226 | configurable: false,
|
227 | enumerable: false,
|
228 | writable: false,
|
229 | value: val
|
230 | });
|
231 | }
|
232 |
|
233 | module.exports.SecureValue = SecureValue;
|
234 |
|
235 | SecureValue.prototype.toString = function() {
|
236 | return '********';
|
237 | };
|
238 |
|
239 | SecureValue.prototype.getValue = function () {
|
240 | return this.value;
|
241 | };
|