-
Notifications
You must be signed in to change notification settings - Fork 626
Expand file tree
/
Copy pathutil.js
More file actions
240 lines (200 loc) · 6.4 KB
/
util.js
File metadata and controls
240 lines (200 loc) · 6.4 KB
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
require('shelljs/global');
// Utilities from shelljs
/* globals exit which */
const fs = require('fs');
const util = {};
const _ = require('lodash');
const cliVersion = require('../package.json').version;
const confUtils = require('./conf-utils');
const { execSync } = require('child_process');
const semver = require('semver');
const ora = require('ora');
const { spawn } = require('child_process');
module.exports = util;
const prefix = ' Apostrophe '.black.bgWhite.bold;
util.styleCommand = function(commandName, style) {
const bgStyle = style === 'danger'
? 'bgRed'
: style === 'success' ? 'bgGreen' : 'bgBlue';
return ' '[bgStyle] + commandName[bgStyle].white + ' '[bgStyle];
};
util.log = function(commandName, message) {
console.log(' ');
console.log(prefix + util.styleCommand(commandName) + ' ' + message);
};
util.success = async function(commandName) {
console.log(' ');
console.log(prefix + util.styleCommand(commandName, 'success') + ' Finished successfully.'.green);
try {
await checkIfUpdated();
} catch (error) {
console.error(error);
}
};
util.error = async function(commandName, msg) {
console.error(' ');
console.error(prefix + util.styleCommand(commandName, 'danger') + ' Failed'.red);
if (msg) {
console.error('\n' + msg.red + '\n');
}
try {
await checkIfUpdated();
} catch (error) {
console.error(error);
}
};
util.notValid = function(commandName) {
console.log(' ');
console.log(prefix + ' Not a valid command'.red);
};
util.isWindows = (require('os').platform() === 'win32');
util.missingDependency = function(dependencyName) {
console.log(' ');
console.log(dependencyName + ' not found'.red);
console.log('Please install missing dependency'.red);
};
util.checkDependencies = function() {
const config = require('../config');
for (const i in config.SHELL_DEPENDS) {
const dep = config.SHELL_DEPENDS[i];
if (!which(dep)) {
util.missingDependency(dep);
exit(1);
}
}
};
util.getAppPath = async function(command, path) {
path = path || './';
if (fs.existsSync(path + '/app.js')) {
return path;
} else {
let rootPath = /\/$/;
// In case of Windows, top level directory is some variation on C:\
if (util.isWindows) {
rootPath = /([A-Z]):\\$/;
}
if (fs.realpathSync(path).match(rootPath)) {
// we've reached top level folder, no app.js
await util.error(command, 'Unable to locate an app.js in this directory. You need to be in the root directory of an Apostrophe project to run this command.');
return null;
}
return util.getAppPath(command, path + '../');
}
};
util.isEsm = async function(command, path) {
const appPath = await util.getAppPath(command, path);
let info;
try {
info = JSON.parse(fs.readFileSync(`${appPath}/package.json`));
} catch (e) {
await util.error('package.json is missing or invalid.');
return null;
}
console.log(`isEsm: ${info.type === 'module'}`);
return info.type === 'module';
};
util.esmify = function(code, isEsm) {
if (!isEsm) {
return code;
}
return code.replace('module.exports =', 'export default');
};
util.getMajorVersion = async (command, v) => {
if (!v) {
await util.error(command, 'Unable to identify the installed version of Apostrophe. Please install packages before creating modules with the CLI tool.');
return null;
}
return v.split('.')[0];
};
util.getStrings = (version, command, moduleName, options) => {
const allStrings = require('./boilerplate')(moduleName, options);
return allStrings[version][command];
};
util.titleCase = function(string) {
return string.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
};
// Replace the given regexp with the given replacement in all of the files in
// the given array.
// As always, if you want global replace within the file, use `/g`
util.replaceInFiles = function(files, regex, replacement) {
_.each(files, function(file) {
let content = fs.readFileSync(file, 'utf8');
content = content.replace(regex, replacement);
fs.writeFileSync(file, content);
});
};
util.secret = function() {
const bytes = require('crypto').randomBytes(8);
let string = '';
let i;
for (i = 0; (i < bytes.length); i++) {
let s = bytes[i].toString(16);
if (s.length < 2) {
s = '0' + s;
}
string += s;
}
return string;
};
util.spawnWithSpinner = async function (command, options = {
spinnerMessage: 'Processing...',
codeMessage: 'Spawn process error code:'
}) {
if (!command) {
throw new Error('No command provided to spawnWithSpinner');
}
const spinner = ora({
text: options.spinnerMessage,
interval: 100,
isEnabled: true
});
return new Promise((resolve, reject) => {
try {
const spawned = spawn(command, {
shell: true
});
spinner.start();
let output = '';
spawned.stdout.on('data', (data) => {
output += data.toString();
});
spawned.stderr.on('data', (data) => {
output += data.toString();
});
spawned.on('exit', (code) => {
spinner.stop();
if (code !== null && code !== 0) {
return reject(new Error(output));
}
// Log the install process output. Not using the CLI logging utility
// since this isn't CLI messaging.
console.log(output);
return resolve();
});
} catch (error) {
return reject(error);
}
});
};
async function checkIfUpdated () {
try {
// Get the latest published version number.
const latest = execSync('npm show @apostrophecms/cli version', { encoding: 'utf8' }).trim();
// Check if they've been notified for this version already. If so, bail out.
const latestChecked = await confUtils.getConf('versionNotified');
if (latestChecked && semver.gte(latestChecked, latest)) {
return;
}
// If the local is behind the published version, suggest updating it.
if (semver.gt(latest, cliVersion)) {
console.log(`\n🆕 There is an updated version of the @apostrophecms/cli module. The latest is ${latest}. You are on ${cliVersion}.\nUse \`npm i -g @apostrophecms/cli\` to get the latest version.`);
}
// Stash the last notified version in user conf.
confUtils.setConf('versionNotified', latest);
} catch (error) {
// Unable to check the latest version of the CLI package for some reason.
// No need to interrupt the user.
}
}