1 |
|
2 |
|
3 | const argv = process.argv.slice(2);
|
4 |
|
5 |
|
6 | const win = process.platform === 'win32';
|
7 | const cwd = process.cwd();
|
8 | const etc = '/etc';
|
9 |
|
10 | const home = win
|
11 | ? process.env.USERPROFILE
|
12 | : process.env.HOME;
|
13 |
|
14 | let _task = 'default';
|
15 |
|
16 |
|
17 | if (/^(?!-)[\w:-]+$/.test(argv[0])) {
|
18 | _task = argv.shift() || _task;
|
19 | }
|
20 |
|
21 | let $;
|
22 |
|
23 | try {
|
24 | $ = require('wargs')(argv, {
|
25 | camelCase: true,
|
26 | boolean: 'ODIGRCAVvdqfhba',
|
27 | alias: {
|
28 | O: 'no-install-opts',
|
29 | D: 'no-install-dev',
|
30 | I: 'no-install',
|
31 | G: 'no-clone',
|
32 | R: 'no-exec',
|
33 | C: 'no-copy',
|
34 | A: 'no-add',
|
35 | V: 'verbose',
|
36 | v: 'version',
|
37 | d: 'debug',
|
38 | q: 'quiet',
|
39 | f: 'force',
|
40 | e: 'entry',
|
41 | g: 'gist',
|
42 | h: 'help',
|
43 | b: 'bare',
|
44 | a: 'ask',
|
45 | },
|
46 | });
|
47 | } catch (e) {
|
48 | process.stderr.write(`\r\x1b[31m${e.message}\x1b[0m\n`);
|
49 | process.exit(1);
|
50 | }
|
51 |
|
52 | const cleanStack = require('clean-stack');
|
53 | const path = require('path');
|
54 | const fs = require('fs');
|
55 |
|
56 |
|
57 | const log = require('log-pose')
|
58 | .getLogger(12, process.stdout, process.stderr);
|
59 |
|
60 | const Haki = require('../lib');
|
61 | const util = require('../lib/utils');
|
62 | const thisPkg = require('../package.json');
|
63 |
|
64 | const CONFIG = {};
|
65 | const CACHE = [];
|
66 |
|
67 | const _gists = path.join(home, '.config', thisPkg.name, 'gists');
|
68 |
|
69 |
|
70 | if (!fs.existsSync(path.dirname(_gists))) {
|
71 | fs.mkdirSync(path.dirname(_gists));
|
72 | }
|
73 |
|
74 |
|
75 | if (!fs.existsSync(_gists)) {
|
76 | fs.mkdirSync(_gists);
|
77 | }
|
78 |
|
79 | let depth = 20;
|
80 | let pwd = cwd;
|
81 | let tmp;
|
82 |
|
83 | const haki = new Haki(util.extend({}, $.flags, { data: $._ }));
|
84 |
|
85 | if ($.flags.entry) {
|
86 | haki.load(path.resolve($.flags.entry));
|
87 | }
|
88 |
|
89 | function showError(e) {
|
90 | log.printf('{% fail %s %}\r\n', ($.flags.debug && cleanStack(e.stack)) || e.message);
|
91 | }
|
92 |
|
93 | function showHelp(tasks) {
|
94 | log.write('\r\n Usage:\n haki COMMAND [...]\n');
|
95 |
|
96 |
|
97 | if (tasks.length) {
|
98 | tasks.forEach(params => {
|
99 | log.write(` haki ${util.padding(params.name, 20)}${
|
100 | params.message ? [' # ', params.message].join('') : ''
|
101 | }\n`);
|
102 | });
|
103 | }
|
104 |
|
105 | log.write(`
|
106 | Options:
|
107 | -g, ${util.padding('[--gist]', 15)} # Manage and download gists (e.g. -g 7f473b462ca7ecd3f648853ba6e44e2a)
|
108 | -f, ${util.padding('[--force]', 15)} # Overwrite files that already exist
|
109 | -f, ${util.padding('[--verbose]', 15)} # Display more information on logs
|
110 | -v, ${util.padding('[--version]', 15)} # Print version and quit
|
111 | -d, ${util.padding('[--debug]', 15)} # Print stack on error
|
112 | -q, ${util.padding('[--quiet]', 15)} # Supress status output
|
113 | -b, ${util.padding('[--bare]', 15)} # Remove additional logs
|
114 | -b, ${util.padding('[--ask]', 15)} # Choose from registered tasks
|
115 | -h, ${util.padding('[--help]', 15)} # Show this help message
|
116 |
|
117 | `);
|
118 |
|
119 |
|
120 | if ($.flags.verbose) {
|
121 | log.write(' Hakifiles:\n');
|
122 |
|
123 | CACHE.forEach(file => {
|
124 | log.write(` ${file}\n`);
|
125 | });
|
126 |
|
127 | log.write('\n');
|
128 | }
|
129 | }
|
130 |
|
131 | function gists(id) {
|
132 |
|
133 | if (!tmp) {
|
134 | tmp = {};
|
135 | fs.readdirSync(_gists)
|
136 | .filter(src => src.indexOf('.json') > -1)
|
137 | .forEach(src => {
|
138 | tmp[path.basename(src, '.json')] = require(path.join(_gists, src));
|
139 | });
|
140 | }
|
141 |
|
142 |
|
143 | if (id) {
|
144 | return tmp[id];
|
145 | }
|
146 |
|
147 | return tmp;
|
148 | }
|
149 |
|
150 | function detail(data) {
|
151 | log.printf('{% link %s %}\r\n', data.html_url);
|
152 | log.printf(' {% gray %s <%s> %}\r\n', data.updated_at, data.owner.login);
|
153 | log.printf(' {% gray %s %}\r\n', data.description);
|
154 | }
|
155 |
|
156 | function setup(id, data) {
|
157 | return Promise.resolve()
|
158 | .then(() => {
|
159 |
|
160 | if (data.message) {
|
161 | log.printf('\r\r{% warn %s %}\n', data.message);
|
162 | log.printf('{% link %s %}\n', data.documentation_url);
|
163 | util.die(1);
|
164 | }
|
165 |
|
166 |
|
167 | if (!(data.files && data.files['Hakifile.js'])) {
|
168 | throw new Error(`Gist ${data.html_url} does not contains a Hakifile.js`);
|
169 | }
|
170 |
|
171 | const dir = path.join(_gists, id);
|
172 |
|
173 |
|
174 | if (!fs.existsSync(dir)) {
|
175 | fs.mkdirSync(dir);
|
176 | }
|
177 |
|
178 | Object.keys(data.files).forEach(src => {
|
179 | fs.writeFileSync(path.join(dir, src), data.files[src].content);
|
180 | });
|
181 |
|
182 | detail(data);
|
183 | });
|
184 | }
|
185 |
|
186 | function save(id, data) {
|
187 | try {
|
188 | return setup(id, data).then(() => {
|
189 | fs.writeFileSync(path.join(_gists, `${id}.json`), JSON.stringify(data));
|
190 | util.die();
|
191 | }).catch(e => {
|
192 | showError(e);
|
193 | util.die(1);
|
194 | });
|
195 | } catch (e) {
|
196 | showError(e);
|
197 | util.die(1);
|
198 | }
|
199 | }
|
200 |
|
201 | function load(filepath) {
|
202 |
|
203 | if (CACHE.indexOf(filepath) > -1) {
|
204 | return;
|
205 | }
|
206 |
|
207 | try {
|
208 |
|
209 | if (fs.existsSync(filepath)) {
|
210 | if (fs.statSync(filepath).isDirectory()) {
|
211 | const Hakifile = fs.readdirSync(filepath)
|
212 | .filter(file => file.indexOf('Hakifile') > -1);
|
213 |
|
214 |
|
215 | if (Hakifile.length) {
|
216 | require(path.join(filepath, Hakifile[0]))(haki);
|
217 | CACHE.push(filepath);
|
218 | }
|
219 | } else {
|
220 | util.extend(CONFIG, JSON.parse(fs.readFileSync(filepath).toString()));
|
221 | }
|
222 | }
|
223 | } catch (e) {
|
224 | showError(e);
|
225 | util.die(1);
|
226 | }
|
227 | }
|
228 |
|
229 | function list() {
|
230 | log.printf('{% info Listing gists from %s %}\n', _gists);
|
231 |
|
232 | const src = gists();
|
233 | const keys = Object.keys(src).length;
|
234 |
|
235 | Object.keys(src).forEach(key => {
|
236 | detail(src[key]);
|
237 | });
|
238 |
|
239 | log.printf('{% log %s gist%s found %}\n', keys, keys === 1 ? '' : 's');
|
240 | }
|
241 |
|
242 | function get(id) {
|
243 | try {
|
244 | log(false, `Fetching Gist ${id} ...`, () => {
|
245 |
|
246 | if (gists(id) && $.flags.force !== true) {
|
247 | showError(new Error(`Gist ${id} already installed`));
|
248 | util.die(1);
|
249 | }
|
250 |
|
251 | return new Promise((resolve, reject) => {
|
252 | let data = '';
|
253 |
|
254 | require('https').get({
|
255 | path: `/gists/${id}`,
|
256 | host: 'api.github.com',
|
257 | headers: {
|
258 | 'User-Agent': `NodeJS/Haki v${thisPkg.version}`,
|
259 | },
|
260 | }, res => {
|
261 | res.on('data', chunk => {
|
262 | data += chunk;
|
263 | });
|
264 |
|
265 | res.on('end', () => {
|
266 | try {
|
267 | save(id, JSON.parse(data))
|
268 | .then(resolve)
|
269 | .catch(reject);
|
270 | } catch (e) {
|
271 | reject(e);
|
272 | }
|
273 | });
|
274 | }).on('error', e => {
|
275 | reject(e);
|
276 | });
|
277 | }).catch(e => {
|
278 | showError(e);
|
279 | util.die(1);
|
280 | });
|
281 | });
|
282 | } catch (e) {
|
283 | showError(e);
|
284 | util.die(1);
|
285 | }
|
286 | }
|
287 |
|
288 | function run() {
|
289 | if (!$.flags.bare) {
|
290 | log.printf('{% wait Finding Hakifile(s) ... %}\r\r');
|
291 |
|
292 |
|
293 | require('./Hakifile')(haki);
|
294 |
|
295 | load(path.join(etc, '.config', thisPkg.name));
|
296 | load(path.join(etc, `.${thisPkg.name}rc`));
|
297 |
|
298 | load(path.join(home, '.config', thisPkg.name));
|
299 | load(path.join(home, `.${thisPkg.name}rc`));
|
300 |
|
301 | while (depth > 0) {
|
302 | load(path.join(pwd, '.config', thisPkg.name));
|
303 | load(path.join(pwd, `.${thisPkg.name}rc`));
|
304 | load(pwd);
|
305 |
|
306 | pwd = path.dirname(pwd);
|
307 |
|
308 | depth -= 1;
|
309 |
|
310 |
|
311 | if (pwd === '/' || pwd === home) {
|
312 | break;
|
313 | }
|
314 | }
|
315 |
|
316 |
|
317 | Object.keys(gists()).forEach(id => {
|
318 | load(path.join(_gists, id));
|
319 | });
|
320 |
|
321 | log.printf('{% log %s Hakifile%s found %}\r\n', CACHE.length, CACHE.length === 1 ? '' : 's');
|
322 | }
|
323 |
|
324 |
|
325 | if ($.flags.help) {
|
326 | showHelp(haki.getGeneratorList());
|
327 | util.die();
|
328 | }
|
329 |
|
330 | if (haki.hasGenerator(_task)) {
|
331 | haki.runGenerator(_task, util.extend({}, $.data, $.params, CONFIG))
|
332 | .catch(e => {
|
333 | showError(e);
|
334 | util.die(1);
|
335 | });
|
336 | } else {
|
337 | log.printf('{% fail Missing `%s` generator %}\r\n', _task);
|
338 | util.die(1);
|
339 | }
|
340 | }
|
341 |
|
342 |
|
343 | if ($.flags.version) {
|
344 | log.printf('{% green %s v%s %} {% gray (node %s) %}\n',
|
345 | thisPkg.name, thisPkg.version, process.version);
|
346 | util.die();
|
347 | }
|
348 |
|
349 | if (!$.flags.bare) {
|
350 | log.printf('{% green Haki v%s %} {% gray (%s in %s) %}\n', thisPkg.version, _task, process.env.NODE_ENV || '?');
|
351 | }
|
352 |
|
353 | process.on('exit', statusCode => {
|
354 |
|
355 | if (!statusCode && !$.flags.bare) {
|
356 | log.printf('\r\r{% end Done. %}\r\n');
|
357 | }
|
358 | util.die();
|
359 | });
|
360 |
|
361 |
|
362 | if ($.flags.gist) {
|
363 |
|
364 | if ($.flags.gist !== true) {
|
365 | get($.flags.gist);
|
366 | } else {
|
367 | list();
|
368 | }
|
369 | } else if ($.flags.ask) {
|
370 | haki.chooseGeneratorList()
|
371 | .catch(e => {
|
372 | showError(e);
|
373 | util.die(1);
|
374 | });
|
375 | } else {
|
376 | run();
|
377 | }
|