mythix-cli 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mythix-cli.js +30 -246
- package/bin/runner.js +395 -0
- package/package.json +7 -4
- package/.vscode/settings.json +0 -7
package/bin/mythix-cli.js
CHANGED
|
@@ -1,90 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const Path
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const { hideBin } = require('yargs/helpers');
|
|
7
|
-
const SimpleYargs = require('simple-yargs');
|
|
8
|
-
const { spawn } = require('child_process');
|
|
3
|
+
const Path = require('path');
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
|
+
const { CMDed, Types } = require('cmded');
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
createHash,
|
|
12
|
-
randomFillSync,
|
|
13
|
-
} = require('crypto');
|
|
14
|
-
|
|
15
|
-
function randomBytes(length) {
|
|
16
|
-
var buffer = Buffer.alloc(length);
|
|
17
|
-
randomFillSync(buffer);
|
|
18
|
-
|
|
19
|
-
return buffer;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function SHA256(data) {
|
|
23
|
-
var hash = createHash('sha256');
|
|
24
|
-
hash.update(data);
|
|
25
|
-
return hash.digest('hex');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function SHA512(data) {
|
|
29
|
-
var hash = createHash('sha512');
|
|
30
|
-
hash.update(data);
|
|
31
|
-
return hash.digest('hex');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function randomHash(type = 'sha256', length = 128) {
|
|
35
|
-
var bytes = randomBytes(length);
|
|
36
|
-
var hash = createHash(type);
|
|
37
|
-
|
|
38
|
-
hash.update(bytes);
|
|
39
|
-
|
|
40
|
-
return hash.digest('hex');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function walkDir(rootPath, _options, _callback, _allFiles, _depth) {
|
|
44
|
-
var depth = _depth || 0;
|
|
45
|
-
var allFiles = _allFiles || [];
|
|
46
|
-
var callback = (typeof _options === 'function') ? _options : _callback;
|
|
47
|
-
var options = (typeof _options !== 'function' && _options) ? _options : {};
|
|
48
|
-
var filterFunc = options.filter;
|
|
49
|
-
var fileNames = FileSystem.readdirSync(rootPath);
|
|
50
|
-
|
|
51
|
-
for (var i = 0, il = fileNames.length; i < il; i++) {
|
|
52
|
-
var fileName = fileNames[i];
|
|
53
|
-
var fullFileName = Path.join(rootPath, fileName);
|
|
54
|
-
var stats = FileSystem.statSync(fullFileName);
|
|
55
|
-
|
|
56
|
-
if (typeof filterFunc === 'function' && !filterFunc(fullFileName, fileName, stats, rootPath, depth))
|
|
57
|
-
continue;
|
|
58
|
-
else if (filterFunc instanceof RegExp && !filterFunc.match(fullFileName))
|
|
59
|
-
continue;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (stats.isDirectory()) {
|
|
63
|
-
walkDir(fullFileName, options, callback, allFiles, depth + 1);
|
|
64
|
-
|
|
65
|
-
if (typeof callback === 'function')
|
|
66
|
-
callback(fullFileName, fileName, rootPath, depth, stats);
|
|
67
|
-
} else if (stats.isFile()) {
|
|
68
|
-
if (typeof callback === 'function')
|
|
69
|
-
callback(fullFileName, fileName, rootPath, depth, stats);
|
|
70
|
-
|
|
71
|
-
allFiles.push(fullFileName);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return allFiles;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function spawnProcess(name, args, options) {
|
|
7
|
+
function spawnCommand(command, args, options) {
|
|
79
8
|
return new Promise((resolve, reject) => {
|
|
80
9
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
10
|
+
let childProcess = spawn(
|
|
11
|
+
command,
|
|
83
12
|
args,
|
|
84
13
|
Object.assign({}, options || {}, {
|
|
85
14
|
env: Object.assign({}, process.env, (options || {}).env || {}),
|
|
86
15
|
stdio: 'inherit',
|
|
87
|
-
})
|
|
16
|
+
}),
|
|
88
17
|
);
|
|
89
18
|
|
|
90
19
|
childProcess.on('error', (error) => {
|
|
@@ -92,11 +21,6 @@ function spawnProcess(name, args, options) {
|
|
|
92
21
|
});
|
|
93
22
|
|
|
94
23
|
childProcess.on('close', (code) => {
|
|
95
|
-
if (code !== 0) {
|
|
96
|
-
var error = new Error(`Process ${name} exited with non-zero code`);
|
|
97
|
-
return reject(error);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
24
|
resolve(code);
|
|
101
25
|
});
|
|
102
26
|
} catch (error) {
|
|
@@ -105,181 +29,41 @@ function spawnProcess(name, args, options) {
|
|
|
105
29
|
});
|
|
106
30
|
}
|
|
107
31
|
|
|
108
|
-
function
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
context.APP_NAME = () => appName;
|
|
112
|
-
context.RANDOM_SHA256 = () => randomHash('sha256');
|
|
113
|
-
|
|
114
|
-
return context;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function getTemplatedFileName(fileName, context) {
|
|
118
|
-
return fileName.replace(/__([A-Z0-9_]+)__/g, function(m, varName) {
|
|
119
|
-
var func = context[varName];
|
|
120
|
-
if (typeof func !== 'function')
|
|
121
|
-
return '';
|
|
122
|
-
|
|
123
|
-
return func();
|
|
124
|
-
}).replace(/__/g, '');
|
|
125
|
-
}
|
|
32
|
+
(async function () {
|
|
33
|
+
let config;
|
|
126
34
|
|
|
127
|
-
|
|
128
|
-
|
|
35
|
+
let argOptions = CMDed(({ $, store }) => {
|
|
36
|
+
$('--config', Types.STRING({
|
|
37
|
+
format: Path.resolve,
|
|
38
|
+
})) || store({ config: Path.join(process.env.PWD, '.mythix-config.js') });
|
|
129
39
|
|
|
130
|
-
|
|
131
|
-
var func = context[varName];
|
|
40
|
+
$('--runtime', Types.STRING());
|
|
132
41
|
|
|
133
|
-
|
|
134
|
-
return '';
|
|
135
|
-
|
|
136
|
-
return func();
|
|
42
|
+
return true;
|
|
137
43
|
});
|
|
138
44
|
|
|
139
|
-
if (newContent === content)
|
|
140
|
-
return;
|
|
141
|
-
|
|
142
|
-
FileSystem.writeFileSync(fullFileName, newContent, 'utf8');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function runTemplateEngineOnProject(projectPath, context) {
|
|
146
|
-
walkDir(
|
|
147
|
-
projectPath,
|
|
148
|
-
{
|
|
149
|
-
filter: (fullFileName, fileName, stats) => {
|
|
150
|
-
if (fileName === 'node_modules' && stats.isDirectory())
|
|
151
|
-
return false;
|
|
152
|
-
|
|
153
|
-
return true;
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
(_fullFileName, _fileName, rootPath, depth, stats) => {
|
|
157
|
-
var fullFileName = _fullFileName;
|
|
158
|
-
var fileName = _fileName;
|
|
159
|
-
|
|
160
|
-
var newFileName = getTemplatedFileName(fileName, context);
|
|
161
|
-
if (newFileName !== fileName) {
|
|
162
|
-
fileName = newFileName;
|
|
163
|
-
|
|
164
|
-
newFileName = Path.resolve(Path.dirname(fullFileName), newFileName);
|
|
165
|
-
|
|
166
|
-
FileSystem.renameSync(fullFileName, newFileName)
|
|
167
|
-
|
|
168
|
-
fullFileName = newFileName;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (stats.isFile())
|
|
172
|
-
runTemplateOnFile(fullFileName, context);
|
|
173
|
-
}
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async function initApplication(_, args) {
|
|
178
|
-
if (!args.dir || !('' + args.dir).match(/\S/))
|
|
179
|
-
args.dir = Path.resolve(process.env.PWD);
|
|
180
|
-
else
|
|
181
|
-
args.dir = Path.resolve(args.dir);
|
|
182
|
-
|
|
183
45
|
try {
|
|
184
|
-
|
|
185
|
-
var processArgs = [ args.template, templateClonePath ];
|
|
186
|
-
|
|
187
|
-
if (args.tag && args.tag.match(/\S/))
|
|
188
|
-
processArgs = [ '-b', args.tag ].concat(processArgs);
|
|
189
|
-
|
|
190
|
-
await spawnProcess('git', [ 'clone' ].concat(processArgs));
|
|
191
|
-
|
|
192
|
-
FileSystem.rmSync(Path.resolve(templateClonePath, '.git'), { recursive: true, force: true });
|
|
193
|
-
|
|
194
|
-
runTemplateEngineOnProject(templateClonePath, createTemplateEngineContext(args.appName));
|
|
195
|
-
|
|
196
|
-
await spawnProcess('npm', [ 'i' ], { env: { PWD: templateClonePath, CWD: templateClonePath }, cwd: templateClonePath });
|
|
197
|
-
|
|
198
|
-
console.log(`Empty mythix project created at ${templateClonePath}`);
|
|
199
|
-
console.log('To finalize setup you need to:');
|
|
200
|
-
console.log(' 1) Select and configure the correct database driver for Sequelize');
|
|
201
|
-
console.log(' 2) Define the models for your application');
|
|
202
|
-
console.log(' 3) Create an initial migration for your models: `npx mythix-cli makemigrations --name initial`');
|
|
203
|
-
console.log(' 4) Run migrations: `npx mythix-cli migrate`');
|
|
204
|
-
console.log(' 5) Finally run your application: `npx mythix-cli serve`');
|
|
46
|
+
config = require(argOptions.config);
|
|
205
47
|
} catch (error) {
|
|
206
|
-
|
|
48
|
+
config = {};
|
|
207
49
|
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function createYargsCommands(yargs, commandsObj, actionHandler) {
|
|
211
|
-
var commands = [];
|
|
212
|
-
var commandNames = Object.keys(commandsObj);
|
|
213
50
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
51
|
+
const args = process.argv.slice(2);
|
|
52
|
+
const runtime = argOptions.runtime || config.runtime || 'node';
|
|
53
|
+
const runtimeArgs = config.runtimeArgs || [];
|
|
54
|
+
const commands = [ runtime, (process.platform == 'win32') ? `${runtime}.cmd` : undefined ].filter(Boolean);
|
|
217
55
|
|
|
218
|
-
|
|
219
|
-
|
|
56
|
+
for (let i = 0, il = commands.length; i < il; i++) {
|
|
57
|
+
let command = commands[i];
|
|
220
58
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
(async function() {
|
|
230
|
-
const packageJSONPath = Path.resolve(__dirname, '..', 'package.json');
|
|
231
|
-
const packageJSON = require(packageJSONPath);
|
|
232
|
-
|
|
233
|
-
// Windows hack
|
|
234
|
-
if(!process.env.PWD)
|
|
235
|
-
process.env.PWD = process.cwd();
|
|
236
|
-
|
|
237
|
-
var PWD = process.env.PWD;
|
|
238
|
-
var argv = hideBin(process.argv);
|
|
239
|
-
var rootCommand;
|
|
240
|
-
|
|
241
|
-
try {
|
|
242
|
-
if (argv[0] !== 'init') {
|
|
243
|
-
argv = hideBin(process.argv).concat('');
|
|
244
|
-
rootCommand = yargs(argv);
|
|
245
|
-
|
|
246
|
-
var mythixPath = Path.dirname(require.resolve('mythix', { paths: [ process.env.PWD, Path.resolve(process.env.PWD, 'node_modules') ] }));
|
|
247
|
-
var mythixCLIPAth = Path.resolve(mythixPath, 'cli');
|
|
248
|
-
var mythixCLI = require(mythixCLIPAth);
|
|
249
|
-
var config = mythixCLI.loadMythixConfig(PWD);
|
|
250
|
-
|
|
251
|
-
var Application = config.getApplicationClass(config);
|
|
252
|
-
if (typeof Application !== 'function')
|
|
253
|
-
throw new Error('Expected to find an Application class from "getApplicationClass", but none was returned.');
|
|
254
|
-
|
|
255
|
-
var application = await mythixCLI.createApplication(Application, { autoReload: false, database: false, httpServer: false });
|
|
256
|
-
var applicationOptions = application.getOptions();
|
|
257
|
-
|
|
258
|
-
var commands = await mythixCLI.loadCommands(applicationOptions.commandsPath);
|
|
259
|
-
|
|
260
|
-
rootCommand = createYargsCommands(rootCommand, commands, async function(command, commandPath) {
|
|
261
|
-
await mythixCLI.executeCommand(
|
|
262
|
-
config.configPath,
|
|
263
|
-
applicationOptions.commandsPath,
|
|
264
|
-
Path.dirname(require.resolve('yargs')),
|
|
265
|
-
Path.dirname(require.resolve('simple-yargs', '..')),
|
|
266
|
-
argv,
|
|
267
|
-
commandPath,
|
|
268
|
-
command,
|
|
269
|
-
config,
|
|
270
|
-
);
|
|
59
|
+
try {
|
|
60
|
+
await spawnCommand(command, runtimeArgs.concat([ Path.resolve(__dirname, 'runner.js') ], args));
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (error.code === 'ENOENT' && (i + 1) < commands.length)
|
|
63
|
+
continue;
|
|
271
64
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
} else {
|
|
275
|
-
argv = hideBin(process.argv);
|
|
276
|
-
rootCommand = yargs(argv);
|
|
65
|
+
console.error(error);
|
|
66
|
+
throw error;
|
|
277
67
|
}
|
|
278
|
-
} catch (error) {
|
|
279
|
-
console.error(mythixPath, error);
|
|
280
68
|
}
|
|
281
|
-
|
|
282
|
-
rootCommand = SimpleYargs.buildCommands(rootCommand, initApplication, [ 'init(Create a new application with the given name) <appName:string(Specify application name)> [-d,-dir:string(Path at which to create application)] [-t,-template:string(Git URL to use to clone and create new project from)=https://github.com/th317erd/mythix-app-template.git(Default "https://github.com/th317erd/mythix-app-template.git")] [-tag:string(Specify tag or commit hash to clone template from)]' ]);
|
|
283
|
-
|
|
284
|
-
rootCommand.version(packageJSON.version).strictCommands().wrap(120).parse();
|
|
285
69
|
})();
|
package/bin/runner.js
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
const Nife = require('nife');
|
|
2
|
+
const Path = require('path');
|
|
3
|
+
const FileSystem = require('fs');
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
CMDed,
|
|
8
|
+
showHelp,
|
|
9
|
+
} = require('cmded');
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
createHash,
|
|
13
|
+
randomFillSync,
|
|
14
|
+
} = require('crypto');
|
|
15
|
+
|
|
16
|
+
function randomBytes(length) {
|
|
17
|
+
let buffer = Buffer.alloc(length);
|
|
18
|
+
randomFillSync(buffer);
|
|
19
|
+
|
|
20
|
+
return buffer;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function randomHash(type = 'sha256', length = 128) {
|
|
24
|
+
let bytes = randomBytes(length);
|
|
25
|
+
let hash = createHash(type);
|
|
26
|
+
|
|
27
|
+
hash.update(bytes);
|
|
28
|
+
|
|
29
|
+
return hash.digest('hex');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function walkDir(rootPath, _options, _callback, _allFiles, _depth) {
|
|
33
|
+
let depth = _depth || 0;
|
|
34
|
+
let allFiles = _allFiles || [];
|
|
35
|
+
let callback = (typeof _options === 'function') ? _options : _callback;
|
|
36
|
+
let options = (typeof _options !== 'function' && _options) ? _options : {};
|
|
37
|
+
let filterFunc = options.filter;
|
|
38
|
+
let fileNames = FileSystem.readdirSync(rootPath);
|
|
39
|
+
|
|
40
|
+
for (let i = 0, il = fileNames.length; i < il; i++) {
|
|
41
|
+
let fileName = fileNames[i];
|
|
42
|
+
let fullFileName = Path.join(rootPath, fileName);
|
|
43
|
+
let stats = FileSystem.statSync(fullFileName);
|
|
44
|
+
|
|
45
|
+
if (typeof filterFunc === 'function' && !filterFunc(fullFileName, fileName, stats, rootPath, depth))
|
|
46
|
+
continue;
|
|
47
|
+
else if (filterFunc instanceof RegExp && !filterFunc.match(fullFileName))
|
|
48
|
+
continue;
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if (stats.isDirectory()) {
|
|
52
|
+
walkDir(fullFileName, options, callback, allFiles, depth + 1);
|
|
53
|
+
|
|
54
|
+
if (typeof callback === 'function')
|
|
55
|
+
callback(fullFileName, fileName, rootPath, depth, stats);
|
|
56
|
+
} else if (stats.isFile()) {
|
|
57
|
+
if (typeof callback === 'function')
|
|
58
|
+
callback(fullFileName, fileName, rootPath, depth, stats);
|
|
59
|
+
|
|
60
|
+
allFiles.push(fullFileName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return allFiles;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function spawnProcess(name, args, options) {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
try {
|
|
70
|
+
let childProcess = spawn(
|
|
71
|
+
name,
|
|
72
|
+
args,
|
|
73
|
+
Object.assign({}, options || {}, {
|
|
74
|
+
env: Object.assign({}, process.env, (options || {}).env || {}),
|
|
75
|
+
stdio: 'inherit',
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
childProcess.on('error', (error) => {
|
|
80
|
+
reject(error);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
childProcess.on('close', (code) => {
|
|
84
|
+
if (code !== 0) {
|
|
85
|
+
let error = new Error(`Process ${name} exited with non-zero code`);
|
|
86
|
+
return reject(error);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
resolve(code);
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
reject(error);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createTemplateEngineContext(appName) {
|
|
98
|
+
let context = Object.create(null);
|
|
99
|
+
|
|
100
|
+
context.APP_NAME = () => appName;
|
|
101
|
+
context.RANDOM_SHA256 = () => randomHash('sha256');
|
|
102
|
+
|
|
103
|
+
return context;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getTemplatedFileName(fileName, context) {
|
|
107
|
+
return fileName.replace(/__([A-Z0-9_]+)__/g, function(m, varName) {
|
|
108
|
+
let func = context[varName];
|
|
109
|
+
if (typeof func !== 'function')
|
|
110
|
+
return '';
|
|
111
|
+
|
|
112
|
+
return func();
|
|
113
|
+
}).replace(/__/g, '');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function runTemplateOnFile(fullFileName, context) {
|
|
117
|
+
let content = FileSystem.readFileSync(fullFileName, 'utf8');
|
|
118
|
+
|
|
119
|
+
let newContent = content.replace(/<<<([A-Z0-9_]+)>>>/g, function(m, varName) {
|
|
120
|
+
let func = context[varName];
|
|
121
|
+
|
|
122
|
+
if (typeof func !== 'function')
|
|
123
|
+
return '';
|
|
124
|
+
|
|
125
|
+
return func();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (newContent === content)
|
|
129
|
+
return;
|
|
130
|
+
|
|
131
|
+
FileSystem.writeFileSync(fullFileName, newContent, 'utf8');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function runTemplateEngineOnProject(projectPath, context) {
|
|
135
|
+
walkDir(
|
|
136
|
+
projectPath,
|
|
137
|
+
{
|
|
138
|
+
filter: (fullFileName, fileName, stats) => {
|
|
139
|
+
if (fileName === 'node_modules' && stats.isDirectory())
|
|
140
|
+
return false;
|
|
141
|
+
|
|
142
|
+
return true;
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
(_fullFileName, _fileName, rootPath, depth, stats) => {
|
|
146
|
+
let fullFileName = _fullFileName;
|
|
147
|
+
let fileName = _fileName;
|
|
148
|
+
|
|
149
|
+
let newFileName = getTemplatedFileName(fileName, context);
|
|
150
|
+
if (newFileName !== fileName) {
|
|
151
|
+
fileName = newFileName;
|
|
152
|
+
|
|
153
|
+
newFileName = Path.resolve(Path.dirname(fullFileName), newFileName);
|
|
154
|
+
|
|
155
|
+
FileSystem.renameSync(fullFileName, newFileName)
|
|
156
|
+
|
|
157
|
+
fullFileName = newFileName;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (stats.isFile())
|
|
161
|
+
runTemplateOnFile(fullFileName, context);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function initApplication(args) {
|
|
167
|
+
if (!args.dir || !('' + args.dir).match(/\S/))
|
|
168
|
+
args.dir = Path.resolve(process.env.PWD);
|
|
169
|
+
else
|
|
170
|
+
args.dir = Path.resolve(args.dir);
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
let templateClonePath = Path.resolve(args.dir, args.appName);
|
|
174
|
+
let processArgs = [ args.template, templateClonePath ];
|
|
175
|
+
let tag;
|
|
176
|
+
|
|
177
|
+
templateClonePath = templateClonePath.replace(/#([^#]+)$/, (m, hash) => {
|
|
178
|
+
tag = hash;
|
|
179
|
+
return '';
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (tag && tag.match(/\S/))
|
|
183
|
+
processArgs = [ '-b', tag ].concat(processArgs);
|
|
184
|
+
|
|
185
|
+
await spawnProcess('git', [ 'clone' ].concat(processArgs));
|
|
186
|
+
|
|
187
|
+
FileSystem.rmSync(Path.resolve(templateClonePath, '.git'), { recursive: true, force: true });
|
|
188
|
+
|
|
189
|
+
runTemplateEngineOnProject(templateClonePath, createTemplateEngineContext(args.appName));
|
|
190
|
+
|
|
191
|
+
await spawnProcess('npm', [ 'i' ], { env: { PWD: templateClonePath, CWD: templateClonePath }, cwd: templateClonePath });
|
|
192
|
+
|
|
193
|
+
console.log(`Empty mythix project created at ${templateClonePath}`);
|
|
194
|
+
console.log('To finalize setup you need to:');
|
|
195
|
+
console.log(' 1) Select and configure the correct database driver for mythix-orm');
|
|
196
|
+
console.log(' 2) Define the models for your application');
|
|
197
|
+
console.log(' 3) Create an initial migration for your models: `npx mythix-cli makemigrations --name initial`');
|
|
198
|
+
console.log(' 4) Run migrations: `npx mythix-cli migrate`');
|
|
199
|
+
console.log(' 5) Finally run your application: `npx mythix-cli serve`');
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error('ERROR: ', error);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function generateCommandHelp(commandsObj, globalHelp) {
|
|
207
|
+
let commandNames = Object.keys(commandsObj || {});
|
|
208
|
+
for (let i = 0, il = commandNames.length; i < il; i++) {
|
|
209
|
+
let commandName = commandNames[i];
|
|
210
|
+
let Klass = commandsObj[commandName];
|
|
211
|
+
let help = null;
|
|
212
|
+
|
|
213
|
+
if (typeof Klass.commandArguments === 'function') {
|
|
214
|
+
let result = (Klass.commandArguments() || {});
|
|
215
|
+
help = result.help;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!help) {
|
|
219
|
+
help = {
|
|
220
|
+
'@usage': `mythix-cli ${commandName}`,
|
|
221
|
+
'@title': `Invoke the "${commandName}" command`,
|
|
222
|
+
'@see': `See: 'mythix-cli test --help' for more help`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (!help['@see'])
|
|
227
|
+
help['@see'] = `See: 'mythix-cli ${commandName} --help' for more help`;
|
|
228
|
+
|
|
229
|
+
globalHelp[commandName] = help;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function commandRunners(commandsObj, context) {
|
|
234
|
+
let commandNames = Object.keys(commandsObj);
|
|
235
|
+
|
|
236
|
+
for (let i = 0, il = commandNames.length; i < il; i++) {
|
|
237
|
+
let commandName = commandNames[i];
|
|
238
|
+
let Klass = commandsObj[commandName];
|
|
239
|
+
let runner = null;
|
|
240
|
+
|
|
241
|
+
if (typeof Klass.commandArguments === 'function') {
|
|
242
|
+
let result = (Klass.commandArguments() || {});
|
|
243
|
+
runner = result.runner;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let result = context.match(commandName, ({ scope, store }, parserResult) => {
|
|
247
|
+
store({ command: commandName });
|
|
248
|
+
|
|
249
|
+
return scope(commandName, (context) => {
|
|
250
|
+
if (typeof runner === 'function')
|
|
251
|
+
return runner(context, parserResult);
|
|
252
|
+
|
|
253
|
+
return true;
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (result)
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
(async function() {
|
|
265
|
+
const packageJSONPath = Path.resolve(__dirname, '..', 'package.json');
|
|
266
|
+
const packageJSON = require(packageJSONPath);
|
|
267
|
+
|
|
268
|
+
// Windows hack
|
|
269
|
+
if(!process.env.PWD)
|
|
270
|
+
process.env.PWD = process.cwd();
|
|
271
|
+
|
|
272
|
+
let argOptions = CMDed(({ $, store, Types }) => {
|
|
273
|
+
$('--config', Types.STRING({
|
|
274
|
+
format: Path.resolve,
|
|
275
|
+
})) || store({ config: (Nife.isNotEmpty(process.env.MYTHIX_CONFIG_PATH)) ? Path.resolve(process.env.MYTHIX_CONFIG_PATH) : Path.join(process.env.PWD, '.mythix-config.js') });
|
|
276
|
+
|
|
277
|
+
$('--runtime', Types.STRING());
|
|
278
|
+
|
|
279
|
+
$('-e', Types.STRING(), { name: 'environment' });
|
|
280
|
+
$('--env', Types.STRING(), { name: 'environment' });
|
|
281
|
+
|
|
282
|
+
$('--version', Types.BOOLEAN());
|
|
283
|
+
|
|
284
|
+
$('--help', Types.BOOLEAN());
|
|
285
|
+
|
|
286
|
+
// Consume to VOID
|
|
287
|
+
$('--', () => {});
|
|
288
|
+
|
|
289
|
+
$('init', ({ scope }) => {
|
|
290
|
+
return scope('init', ({ $ }) => {
|
|
291
|
+
$('--dir', Types.STRING({ format: Path.resolve }), { name: 'dir' })
|
|
292
|
+
|| $('-d', Types.STRING({ format: Path.resolve }), { name: 'dir' })
|
|
293
|
+
|| store({ dir: Path.resolve('./') });
|
|
294
|
+
|
|
295
|
+
$('--template', Types.STRING(), { name: 'template' })
|
|
296
|
+
|| $('-t', Types.STRING(), { name: 'template' })
|
|
297
|
+
|| store({ template: 'https://github.com/th317erd/mythix-app-template.git' });
|
|
298
|
+
|
|
299
|
+
return $(/^([\w](?:[\w-]+)?)$/, ({ store }, parserResult) => {
|
|
300
|
+
store({ name: parserResult.name });
|
|
301
|
+
return true;
|
|
302
|
+
}, {
|
|
303
|
+
formatParserResult: (value) => {
|
|
304
|
+
return { name: value[1] };
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
return true;
|
|
311
|
+
}, { helpArgPattern: null });
|
|
312
|
+
|
|
313
|
+
if (argOptions.version) {
|
|
314
|
+
console.log(packageJSON.version);
|
|
315
|
+
return process.exit(0);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let help = {
|
|
319
|
+
'@usage': 'mythix-cli [command] [options]',
|
|
320
|
+
'@title': 'Run a CLI command',
|
|
321
|
+
'--config={config file path} | --config {config file path}': 'Specify the path to ".mythix-config.js". Default = "{CWD}/.mythix-config.js".',
|
|
322
|
+
'-e={environment} | -e {environment} | --env={environment} | --env {environment}': 'Specify the default environment to use. Default = "development".',
|
|
323
|
+
'--runtime={runtime} | --runtime {runtime}': 'Specify the runtime to use to launch the command. Default = "node"',
|
|
324
|
+
'init': {
|
|
325
|
+
'@usage': 'mythix-cli init app-name [options]',
|
|
326
|
+
'@title': 'Initialize a blank mythix application',
|
|
327
|
+
'@see': 'See: \'mythix-cli init --help\' for more help',
|
|
328
|
+
'-d={path} | -d {path} | --dir={path} | --dir {path}': 'Specify directory to create new application in. Default = "./"',
|
|
329
|
+
'-t={url} | -t {url} | --template={url} | --template {url}': 'Specify a git repository URL to use for a template to create the application with. Default = "https://github.com/th317erd/mythix-app-template.git".'
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
if (argOptions.init) {
|
|
334
|
+
if (Nife.isEmpty(argOptions.init)) {
|
|
335
|
+
showHelp(help.init);
|
|
336
|
+
return process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
await initApplication(argOptions.init);
|
|
340
|
+
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
let rootOptions = { help };
|
|
346
|
+
|
|
347
|
+
let mythixPath = Path.dirname(require.resolve('mythix', { paths: [ process.env.PWD, Path.resolve(process.env.PWD, 'node_modules') ] }));
|
|
348
|
+
let mythixCLIPAth = Path.resolve(mythixPath, 'cli');
|
|
349
|
+
let mythixCLI = require(mythixCLIPAth);
|
|
350
|
+
let config = mythixCLI.loadMythixConfig(argOptions.config);
|
|
351
|
+
|
|
352
|
+
let Application = config.getApplicationClass(config);
|
|
353
|
+
if (typeof Application !== 'function')
|
|
354
|
+
throw new Error('Expected to find an Application class from "getApplicationClass", but none was returned.');
|
|
355
|
+
|
|
356
|
+
let application = await mythixCLI.createApplication(Application, { autoReload: false, database: false, httpServer: false });
|
|
357
|
+
let applicationOptions = application.getOptions();
|
|
358
|
+
|
|
359
|
+
let commands = await mythixCLI.loadCommands(applicationOptions.commandsPath);
|
|
360
|
+
generateCommandHelp(commands, help);
|
|
361
|
+
|
|
362
|
+
let commandContext = CMDed((context) => {
|
|
363
|
+
let { $, Types, store } = context;
|
|
364
|
+
|
|
365
|
+
$('--config', Types.STRING({
|
|
366
|
+
format: Path.resolve,
|
|
367
|
+
})) || store({ config: (Nife.isNotEmpty(process.env.MYTHIX_CONFIG_PATH)) ? Path.resolve(process.env.MYTHIX_CONFIG_PATH) : Path.join(process.env.PWD, '.mythix-config.js') });
|
|
368
|
+
|
|
369
|
+
$('--runtime', Types.STRING());
|
|
370
|
+
|
|
371
|
+
$('-e', Types.STRING(), { name: 'environment' });
|
|
372
|
+
$('--env', Types.STRING(), { name: 'environment' });
|
|
373
|
+
|
|
374
|
+
return commandRunners(commands, context);
|
|
375
|
+
}, rootOptions);
|
|
376
|
+
|
|
377
|
+
if (!commandContext)
|
|
378
|
+
return process.exit(1);
|
|
379
|
+
|
|
380
|
+
await mythixCLI.executeCommand(
|
|
381
|
+
config,
|
|
382
|
+
applicationOptions,
|
|
383
|
+
commandContext,
|
|
384
|
+
commands[commandContext.command],
|
|
385
|
+
process.argv.slice(2),
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
await application.stop();
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error(error);
|
|
391
|
+
}
|
|
392
|
+
// rootCommand = SimpleYargs.buildCommands(rootCommand, initApplication, [ 'init(Create a new application with the given name) <appName:string(Specify application name)> [-d,-dir:string(Path at which to create application)] [-t,-template:string(Git URL to use to clone and create new project from)=https://github.com/th317erd/mythix-app-template.git(Default "https://github.com/th317erd/mythix-app-template.git")] [-tag:string(Specify tag or commit hash to clone template from)]' ]);
|
|
393
|
+
|
|
394
|
+
// rootCommand.version(packageJSON.version).strictCommands().wrap(120).parse();
|
|
395
|
+
})();
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"mythix-cli": "./bin/mythix-cli.js"
|
|
4
4
|
},
|
|
5
5
|
"name": "mythix-cli",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.3.1",
|
|
7
7
|
"description": "Mythix CLI utility",
|
|
8
8
|
"main": "src/index.js",
|
|
9
9
|
"scripts": {
|
|
@@ -27,10 +27,13 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/th317erd/mythix-cli#readme",
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"mythix": "^2.4.
|
|
30
|
+
"mythix": "^2.4.14"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"
|
|
34
|
-
"
|
|
33
|
+
"cmded": "^1.2.1",
|
|
34
|
+
"nife": "^1.11.3"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"eslint": "^8.23.0"
|
|
35
38
|
}
|
|
36
39
|
}
|