/
command.js
174 lines (148 loc) · 5.33 KB
/
command.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
* Inspired by the Denali-CLI command class
* https://github.com/denali-js/denali-cli/blob/master/lib/command.ts
*/
'use strict';
const fs = require('fs-extra');
const UI = require('./ui');
const path = require('path');
const each = require('lodash/each');
const pkg = require('../package.json');
const Config = require('./utils/config');
const createDebug = require('debug');
const kebabCase = require('lodash/kebabCase');
const ServiceManager = require('./services');
const debug = createDebug('ghost-cli:command');
function checkValidInstall(name) {
if (fs.existsSync(path.join(process.cwd(), 'package.json')) &&
fs.readJsonSync(path.join(process.cwd(), 'package.json')).name === 'ghost' &&
fs.existsSync(path.join(process.cwd(), 'Gruntfile.js'))) {
console.error('Ghost-CLI commands do not work inside of a clone or direct download.\n' +
`Perhaps you meant 'grunt ${name}'?`);
process.exit(1);
}
if (!Config.exists(path.join(process.cwd(), '.ghost-cli'))) {
console.error('Working directory is not a valid Ghost installation. ' +
`Please run 'ghost ${name}' again within a valid Ghost installation.`);
process.exit(1);
}
};
/**
* Base Command class
*/
class Command {
/**
* Configures the args/options for this command
*
* @param {String} commandName
* @param {Array<String>} aliases Aliases from abbrev
* @param {Yargs} yargs Yargs instance
*/
static configure(commandName, aliases, yargs) {
if (!this.description) {
throw new Error(`Command ${ commandName } must have a description!`);
}
debug(`adding configuration for ${ commandName }`);
let command = commandName;
if (this.params) {
command += ` ${ this.params }`;
}
return yargs.command({
command: command,
aliases: aliases,
describe: this.description,
builder: (commandArgs) => {
debug(`building options for ${ commandName }`);
commandArgs = this.configureOptions(commandName, commandArgs);
if (this.configureSubcommands) {
commandArgs = this.configureSubcommands(commandName, commandArgs);
}
return commandArgs;
},
handler: (argv) => {
this._run(commandName, argv);
}
});
}
/**
* Configure Yargs for this command
*
* @param {String} commandName Name of the command
* @param {Yargs} yargs Yargs instance
*/
static configureOptions(commandName, yargs) {
if (this.longDescription) {
yargs.usage(this.longDescription);
}
each(this.options || {}, (option, optionName) => {
yargs = yargs.option(kebabCase(optionName), option);
});
return yargs;
}
/**
*
* @param {String} commandName Command Name
* @param {Object} args Parsed arguments
* @param {Object} context Various contextual dependencies
*/
static _run(commandName, argv) {
if (!this.global) {
checkValidInstall(commandName);
}
process.title = `ghost ${ commandName }`;
let verbose = argv.verbose;
let ui = new UI({
verbose: verbose,
allowPrompt: argv.prompt
});
let service = ServiceManager.load(ui);
let context = {
ui: ui,
service: service,
cliVersion: pkg.version
};
context.development = (process.env.NODE_ENV === 'development') || argv.development;
context.environment = context.development ? 'development' : 'production';
// Set NODE_ENV so it's accessible everywhere
process.env.NODE_ENV = context.environment;
// TODO: This is intended to maintain maximum compatability with the pre-yargs
// version of Ghost-CLI - so this will look ugly until the service manager part
// can be refactored.
let commandInstance = new this(context);
debug(`running command ${ commandName }`);
if (commandInstance.cleanup) {
debug(`cleanup handler found for ${ commandName }`);
let cleanup = commandInstance.cleanup.bind(commandInstance);
// process.on('exit') is unreliable apparently, so we do this
process.removeAllListeners('SIGINT').on('SIGINT', cleanup)
.removeAllListeners('SIGTERM').on('SIGTERM', cleanup);
}
return Promise.resolve(commandInstance.run(argv)).catch((error) => {
debug(`command ${ commandName } failed!`);
ui.error(error, {
context: context,
cliVersion: pkg.version
});
process.exit(1);
});
}
/**
* Constructs the command instance
*/
constructor(context) {
// TODO: THIS IS REALLY DIRTY
// Will refactor this out with the service refactors
this.ui = context.ui;
this.service = context.service;
this.cliVersion = context.cliVersion;
this.development = context.development;
this.environment = context.environment;
}
/**
* @param {Object} argv Parsed arguments object
*/
run() {
}
}
module.exports = Command;
module.exports.checkValidInstall = checkValidInstall;