mythix-cli 1.2.1 → 1.3.2
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 +33 -245
- 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,45 @@ function spawnProcess(name, args, options) {
|
|
|
105
29
|
});
|
|
106
30
|
}
|
|
107
31
|
|
|
108
|
-
function
|
|
109
|
-
|
|
32
|
+
(async function () {
|
|
33
|
+
let config;
|
|
110
34
|
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
}
|
|
126
|
-
|
|
127
|
-
function runTemplateOnFile(fullFileName, context) {
|
|
128
|
-
var content = FileSystem.readFileSync(fullFileName, 'utf8');
|
|
35
|
+
// Windows hack
|
|
36
|
+
if(!process.env.PWD)
|
|
37
|
+
process.env.PWD = process.cwd();
|
|
129
38
|
|
|
130
|
-
|
|
131
|
-
|
|
39
|
+
let argOptions = CMDed(({ $, store }) => {
|
|
40
|
+
$('--config', Types.STRING({
|
|
41
|
+
format: Path.resolve,
|
|
42
|
+
})) || store({ config: Path.join(process.env.PWD, '.mythix-config.js') });
|
|
132
43
|
|
|
133
|
-
|
|
134
|
-
return '';
|
|
44
|
+
$('--runtime', Types.STRING());
|
|
135
45
|
|
|
136
|
-
return
|
|
46
|
+
return true;
|
|
137
47
|
});
|
|
138
48
|
|
|
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
49
|
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`');
|
|
50
|
+
config = require(argOptions.config);
|
|
205
51
|
} catch (error) {
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function createYargsCommands(yargs, commandsObj, actionHandler) {
|
|
211
|
-
var commands = [];
|
|
212
|
-
var commandNames = Object.keys(commandsObj);
|
|
213
|
-
|
|
214
|
-
for (var i = 0, il = commandNames.length; i < il; i++) {
|
|
215
|
-
var commandName = commandNames[i];
|
|
216
|
-
var Klass = commandsObj[commandName];
|
|
217
|
-
|
|
218
|
-
commands.push(Klass.commandString);
|
|
52
|
+
config = {};
|
|
219
53
|
}
|
|
220
54
|
|
|
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);
|
|
55
|
+
const args = process.argv.slice(2);
|
|
56
|
+
const runtime = argOptions.runtime || config.runtime || 'node';
|
|
57
|
+
const runtimeArgs = config.runtimeArgs || [];
|
|
58
|
+
const commands = [ runtime, (process.platform == 'win32') ? `${runtime}.cmd` : undefined ].filter(Boolean);
|
|
245
59
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
var mythixCLI = require(mythixCLIPAth);
|
|
249
|
-
var config = mythixCLI.loadMythixConfig(PWD);
|
|
60
|
+
for (let i = 0, il = commands.length; i < il; i++) {
|
|
61
|
+
let command = commands[i];
|
|
250
62
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
);
|
|
63
|
+
try {
|
|
64
|
+
await spawnCommand(command, runtimeArgs.concat([ Path.resolve(__dirname, 'runner.js') ], args));
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (error.code === 'ENOENT' && (i + 1) < commands.length)
|
|
67
|
+
continue;
|
|
271
68
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
} else {
|
|
275
|
-
argv = hideBin(process.argv);
|
|
276
|
-
rootCommand = yargs(argv);
|
|
69
|
+
console.error(error);
|
|
70
|
+
throw error;
|
|
277
71
|
}
|
|
278
|
-
} catch (error) {
|
|
279
|
-
console.error(mythixPath, error);
|
|
280
72
|
}
|
|
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
73
|
})();
|
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.2
|
|
6
|
+
"version": "1.3.2",
|
|
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
|
}
|