@automattic/vip 4.0.0 → 4.0.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/dist/bin/vip-dev-env-sync-sql.js +1 -1
- package/dist/bin/vip-export-sql.js +1 -1
- package/dist/bin/vip-logs.js +1 -1
- package/dist/bin/vip-slowlogs.js +2 -1
- package/dist/lib/cli/command.js +155 -13
- package/dist/lib/dev-environment/dev-environment-core.js +5 -4
- package/dist/lib/dev-environment/dev-environment-lando.js +1 -0
- package/npm-shrinkwrap.json +378 -366
- package/package.json +3 -3
|
@@ -51,7 +51,7 @@ const appQuery = `
|
|
|
51
51
|
requiredArgs: 0,
|
|
52
52
|
module: 'dev-env-sync-sql',
|
|
53
53
|
usage
|
|
54
|
-
}).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option('table', 'The name of a table to include in the partial database sync. Accepts a string value and can be passed more than once with a different value, or add multiple values in a comma-separated list.').option('site-id', 'The ID of a network site to include in the partial database sync. Accepts an integer value (can be passed more than once with different values), or multiple integer values in a comma-separated list.').option('wpcli-command', 'Run a custom WP-CLI command that has logic to retrieve specific data for the partial database export.').option('config-file', 'A local configuration file that specifies the data to include in the partial database sync. Accepts a relative or absolute path to the file.', undefined).option('force', 'Skip validations.', undefined, _devEnvironmentCli.processBooleanOption).examples(examples).argv(process.argv, async (arg, opt) => {
|
|
54
|
+
}).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option('table', 'The name of a table to include in the partial database sync. Accepts a string value and can be passed more than once with a different value, or add multiple values in a comma-separated list.').option('site-id', 'The ID of a network site to include in the partial database sync. Accepts an integer value (can be passed more than once with different values), or multiple integer values in a comma-separated list.', undefined, Number.parseInt).option('wpcli-command', 'Run a custom WP-CLI command that has logic to retrieve specific data for the partial database export.').option('config-file', 'A local configuration file that specifies the data to include in the partial database sync. Accepts a relative or absolute path to the file.', undefined).option('force', 'Skip validations.', undefined, _devEnvironmentCli.processBooleanOption).examples(examples).argv(process.argv, async (arg, opt) => {
|
|
55
55
|
const {
|
|
56
56
|
app,
|
|
57
57
|
env,
|
|
@@ -55,7 +55,7 @@ const appQuery = `
|
|
|
55
55
|
module: 'export-sql',
|
|
56
56
|
requiredArgs: 0,
|
|
57
57
|
usage: 'vip export sql'
|
|
58
|
-
}).option('output', 'Download the file to a specific local directory path with a custom file name.').option('table', 'The name of a table to include in the partial database export. Accepts a string value and can be passed more than once with a different value, or add multiple values in a comma-separated list.').option('site-id', 'The ID of a network site to include in the partial database export. Accepts an integer value and can be passed more than once with a different value, or add multiple values in a comma-separated list.').option('wpcli-command', 'Run a custom WP-CLI command that has logic to retrieve specific data for the partial database export.').option('config-file', 'A local configuration file that specifies the data to include in the partial database export. Accepts a relative or absolute path to the file.', undefined).option('generate-backup', 'Generate a fresh database backup and export an archived copy of that backup.').option('skip-download', 'Skip downloading the file.').examples(examples).argv(process.argv, async (arg, {
|
|
58
|
+
}).option('output', 'Download the file to a specific local directory path with a custom file name.').option('table', 'The name of a table to include in the partial database export. Accepts a string value and can be passed more than once with a different value, or add multiple values in a comma-separated list.').option('site-id', 'The ID of a network site to include in the partial database export. Accepts an integer value and can be passed more than once with a different value, or add multiple values in a comma-separated list.', undefined, Number.parseInt).option('wpcli-command', 'Run a custom WP-CLI command that has logic to retrieve specific data for the partial database export.').option('config-file', 'A local configuration file that specifies the data to include in the partial database export. Accepts a relative or absolute path to the file.', undefined).option('generate-backup', 'Generate a fresh database backup and export an archived copy of that backup.').option('skip-download', 'Skip downloading the file.').examples(examples).argv(process.argv, async (arg, {
|
|
59
59
|
app,
|
|
60
60
|
env,
|
|
61
61
|
output,
|
package/dist/bin/vip-logs.js
CHANGED
|
@@ -218,7 +218,7 @@ const appQuery = exports.appQuery = `
|
|
|
218
218
|
module: 'logs'
|
|
219
219
|
}).option('type', 'Specify the type of Runtime Logs to retrieve. Accepts "batch" (only valid for WordPress environments).', 'app')
|
|
220
220
|
// The default limit is set manually in the validateInputs function to address validation issues, avoiding incorrect replacement of the default value.
|
|
221
|
-
.option('limit', `The maximum number of entries to return. Accepts an integer value between 1 and 5000 (defaults to ${LIMIT_DEFAULT})
|
|
221
|
+
.option('limit', `The maximum number of entries to return. Accepts an integer value between 1 and 5000 (defaults to ${LIMIT_DEFAULT}).`, undefined, Number.parseInt).option('follow', 'Output new entries as they are generated.').option('format', 'Render output in a particular format. Accepts “table“ (default), “csv“, “json“, and “text”.').examples([{
|
|
222
222
|
usage: 'vip @example-app.production logs',
|
|
223
223
|
description: 'Retrieve up to 500 of the most recent entries of application Runtime Logs from web containers.'
|
|
224
224
|
}, {
|
package/dist/bin/vip-slowlogs.js
CHANGED
|
@@ -163,6 +163,7 @@ const appQuery = exports.appQuery = `
|
|
|
163
163
|
name
|
|
164
164
|
}
|
|
165
165
|
`;
|
|
166
|
+
const parseLimit = value => Number.parseInt(String(value), 10);
|
|
166
167
|
void (0, _command.default)({
|
|
167
168
|
appContext: true,
|
|
168
169
|
appQuery,
|
|
@@ -170,7 +171,7 @@ void (0, _command.default)({
|
|
|
170
171
|
format: true,
|
|
171
172
|
module: 'slowlogs',
|
|
172
173
|
usage: baseUsage
|
|
173
|
-
}).option('limit', 'Set the maximum number of log entries. Accepts an integer value between 1 and 500.', 500).examples([{
|
|
174
|
+
}).option('limit', 'Set the maximum number of log entries. Accepts an integer value between 1 and 500.', 500, parseLimit).examples([{
|
|
174
175
|
description: 'Retrieve up to 500 of the most recent entries from the MySQL slow query logs in the default format.',
|
|
175
176
|
usage: exampleUsage
|
|
176
177
|
}, {
|
package/dist/lib/cli/command.js
CHANGED
|
@@ -104,9 +104,13 @@ function createOptionDefinition(name, description, defaultValue, parseFn, usedSh
|
|
|
104
104
|
flags,
|
|
105
105
|
description,
|
|
106
106
|
defaultValue,
|
|
107
|
-
parser
|
|
107
|
+
parser,
|
|
108
|
+
normalizedShortName
|
|
108
109
|
};
|
|
109
110
|
}
|
|
111
|
+
function isOptionToken(arg) {
|
|
112
|
+
return arg !== '-' && arg.startsWith('-');
|
|
113
|
+
}
|
|
110
114
|
class CommanderArgsCompat {
|
|
111
115
|
constructor(opts) {
|
|
112
116
|
this.details = {
|
|
@@ -115,21 +119,43 @@ class CommanderArgsCompat {
|
|
|
115
119
|
this.sub = [];
|
|
116
120
|
this.examplesList = [];
|
|
117
121
|
this.usedShortNames = new Set();
|
|
122
|
+
this.shortOptionsExpectingValue = new Set();
|
|
123
|
+
this.longOptionsExpectingValue = new Set();
|
|
124
|
+
this.knownShortOptions = new Set();
|
|
125
|
+
this.knownLongOptions = new Set();
|
|
118
126
|
this._opts = opts;
|
|
119
127
|
this.program = new _commander.Command();
|
|
120
128
|
this.program.allowUnknownOption(true);
|
|
121
129
|
this.program.allowExcessArguments(true);
|
|
122
130
|
this.program.helpOption(false);
|
|
123
131
|
normalizeUsage(this.program, this._opts.usage);
|
|
132
|
+
this.optionDefaults = new Map();
|
|
124
133
|
}
|
|
125
134
|
option(name, description, defaultValue, parseFn) {
|
|
126
135
|
const definition = createOptionDefinition(name, description, defaultValue, parseFn, this.usedShortNames);
|
|
127
136
|
const {
|
|
128
137
|
flags,
|
|
129
|
-
parser
|
|
138
|
+
parser,
|
|
139
|
+
normalizedShortName
|
|
130
140
|
} = definition;
|
|
141
|
+
const normalizedLongName = String(Array.isArray(name) ? name[1] : name).trim().replace(/^--?/, '');
|
|
142
|
+
const isValueOption = typeof defaultValue !== 'boolean';
|
|
143
|
+
this.knownLongOptions.add(normalizedLongName);
|
|
144
|
+
if (normalizedShortName) {
|
|
145
|
+
this.knownShortOptions.add(normalizedShortName);
|
|
146
|
+
}
|
|
147
|
+
if (isValueOption && normalizedShortName) {
|
|
148
|
+
this.shortOptionsExpectingValue.add(normalizedShortName);
|
|
149
|
+
}
|
|
150
|
+
if (isValueOption) {
|
|
151
|
+
this.longOptionsExpectingValue.add(normalizedLongName);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// When there's a parser, track the default separately and don't pass it to Commander.
|
|
155
|
+
// This prevents the parser from incorrectly accumulating the default value with the first explicit value.
|
|
131
156
|
if (parser && defaultValue !== undefined) {
|
|
132
|
-
this.
|
|
157
|
+
this.optionDefaults.set(normalizedLongName, defaultValue);
|
|
158
|
+
this.program.option(flags, description, parser);
|
|
133
159
|
} else if (parser) {
|
|
134
160
|
this.program.option(flags, description, parser);
|
|
135
161
|
} else if (defaultValue !== undefined) {
|
|
@@ -191,22 +217,128 @@ class CommanderArgsCompat {
|
|
|
191
217
|
return this.details.commands.some(entry => entry.usage === value);
|
|
192
218
|
}
|
|
193
219
|
parse(argv) {
|
|
194
|
-
this.program.parse(argv, {
|
|
220
|
+
this.program.parse(this.normalizeShortOptionEqualsSyntax(argv), {
|
|
195
221
|
from: 'node'
|
|
196
222
|
});
|
|
197
223
|
this.sub = this.program.args.slice();
|
|
198
|
-
|
|
224
|
+
const opts = this.program.opts();
|
|
225
|
+
|
|
226
|
+
// Apply tracked defaults for options with parsers
|
|
227
|
+
for (const [optionName, defaultValue] of this.optionDefaults) {
|
|
228
|
+
if (opts[optionName] === undefined) {
|
|
229
|
+
opts[optionName] = defaultValue;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return opts;
|
|
233
|
+
}
|
|
234
|
+
normalizeShortOptionEqualsSyntax(argv) {
|
|
235
|
+
const normalizedArgv = argv.slice(0, 2);
|
|
236
|
+
for (const arg of argv.slice(2)) {
|
|
237
|
+
const shortOptionEqualsMatch = /^-([A-Za-z0-9])=(.*)$/.exec(arg);
|
|
238
|
+
if (!shortOptionEqualsMatch) {
|
|
239
|
+
normalizedArgv.push(arg);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const shortOptionName = shortOptionEqualsMatch[1];
|
|
243
|
+
const optionValue = shortOptionEqualsMatch[2];
|
|
244
|
+
if (!this.shortOptionsExpectingValue.has(shortOptionName)) {
|
|
245
|
+
normalizedArgv.push(arg);
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
normalizedArgv.push(`-${shortOptionName}`, optionValue);
|
|
249
|
+
}
|
|
250
|
+
return normalizedArgv;
|
|
251
|
+
}
|
|
252
|
+
findSubcommand(argv) {
|
|
253
|
+
const searchStart = argv[2] === '--' ? 3 : 2;
|
|
254
|
+
const dashDashIndex = argv.indexOf('--', searchStart);
|
|
255
|
+
const searchEnd = dashDashIndex === -1 ? argv.length : dashDashIndex;
|
|
256
|
+
for (let index = searchStart; index < searchEnd; index++) {
|
|
257
|
+
const arg = argv[index];
|
|
258
|
+
if (this.isDefined(arg, 'commands')) {
|
|
259
|
+
return {
|
|
260
|
+
index,
|
|
261
|
+
name: arg
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
if (!isOptionToken(arg)) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
const nextArg = argv[index + 1];
|
|
268
|
+
const optionHasInlineValue = arg.includes('=');
|
|
269
|
+
const nextArgCouldBeOptionValue = nextArg && !isOptionToken(nextArg) && !this.isDefined(nextArg, 'commands');
|
|
270
|
+
if (!optionHasInlineValue && nextArgCouldBeOptionValue) {
|
|
271
|
+
index++;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (dashDashIndex > -1 && this.isDefined(argv[dashDashIndex + 1], 'commands')) {
|
|
275
|
+
return {
|
|
276
|
+
index: dashDashIndex + 1,
|
|
277
|
+
name: argv[dashDashIndex + 1]
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
findUnknownOption(argv) {
|
|
283
|
+
const dashDashIndex = argv.indexOf('--', 2);
|
|
284
|
+
const searchEnd = dashDashIndex === -1 ? argv.length : dashDashIndex;
|
|
285
|
+
for (let index = 2; index < searchEnd; index++) {
|
|
286
|
+
const arg = argv[index];
|
|
287
|
+
if (!isOptionToken(arg)) {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (arg.startsWith('--')) {
|
|
291
|
+
const [tokenName] = arg.slice(2).split('=');
|
|
292
|
+
if (!this.knownLongOptions.has(tokenName)) {
|
|
293
|
+
return tokenName;
|
|
294
|
+
}
|
|
295
|
+
const hasInlineValue = arg.includes('=');
|
|
296
|
+
const nextArg = argv[index + 1];
|
|
297
|
+
if (this.longOptionsExpectingValue.has(tokenName) && !hasInlineValue && nextArg && !isOptionToken(nextArg)) {
|
|
298
|
+
index++;
|
|
299
|
+
}
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const shortEqualsMatch = /^-([A-Za-z0-9])=(.*)$/.exec(arg);
|
|
303
|
+
if (shortEqualsMatch) {
|
|
304
|
+
const shortName = shortEqualsMatch[1];
|
|
305
|
+
if (!this.knownShortOptions.has(shortName)) {
|
|
306
|
+
return shortName;
|
|
307
|
+
}
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const shortMatch = /^-([A-Za-z0-9])$/.exec(arg);
|
|
311
|
+
if (shortMatch) {
|
|
312
|
+
const shortName = shortMatch[1];
|
|
313
|
+
if (!this.knownShortOptions.has(shortName)) {
|
|
314
|
+
return shortName;
|
|
315
|
+
}
|
|
316
|
+
const nextArg = argv[index + 1];
|
|
317
|
+
if (this.shortOptionsExpectingValue.has(shortName) && nextArg && !isOptionToken(nextArg)) {
|
|
318
|
+
index++;
|
|
319
|
+
}
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
return arg.replace(/^-+/, '');
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
199
325
|
}
|
|
200
326
|
async executeSubcommand(argv, parsedAlias, subcommand) {
|
|
201
327
|
const currentScript = argv[1];
|
|
328
|
+
const subcommandName = subcommand.name;
|
|
202
329
|
const extension = _nodePath.default.extname(currentScript);
|
|
203
330
|
const baseScriptPath = extension ? currentScript.slice(0, -extension.length) : currentScript;
|
|
204
|
-
const childScriptPath = extension ? `${baseScriptPath}-${
|
|
331
|
+
const childScriptPath = extension ? `${baseScriptPath}-${subcommandName}${extension}` : `${baseScriptPath}-${subcommandName}`;
|
|
205
332
|
const aliasFromRawArgv = argv.slice(2).find(arg => (0, _envAlias.isAlias)(arg));
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
333
|
+
const rawArgsBeforeSubcommand = parsedAlias.argv.slice(2, subcommand.index);
|
|
334
|
+
const hasSeparatorBeforeSubcommand = rawArgsBeforeSubcommand.includes('--');
|
|
335
|
+
const argsBeforeSubcommand = rawArgsBeforeSubcommand.filter(arg => arg !== '--');
|
|
336
|
+
const subcommandArgs = parsedAlias.argv.slice(subcommand.index + 1);
|
|
337
|
+
const hasSeparator = argv.includes('--');
|
|
338
|
+
if (subcommandName === 'wp' && subcommandArgs.length && !hasSeparator) {
|
|
339
|
+
exit.withError('A double dash ("--") must separate the arguments of "vip" from those of "wp". Run "vip wp --help" for examples.');
|
|
340
|
+
}
|
|
341
|
+
let childArgs = [...argsBeforeSubcommand, ...(hasSeparatorBeforeSubcommand ? ['--'] : []), ...subcommandArgs];
|
|
210
342
|
if (aliasFromRawArgv) {
|
|
211
343
|
childArgs = [aliasFromRawArgv, ...childArgs];
|
|
212
344
|
}
|
|
@@ -217,7 +349,7 @@ class CommanderArgsCompat {
|
|
|
217
349
|
env: process.env
|
|
218
350
|
});
|
|
219
351
|
} else {
|
|
220
|
-
const fallbackCommand = `${_nodePath.default.basename(baseScriptPath)}-${
|
|
352
|
+
const fallbackCommand = `${_nodePath.default.basename(baseScriptPath)}-${subcommandName}`;
|
|
221
353
|
if (process.env.VIP_CLI_SEA_MODE === '1' && (0, _internalBinLoader.hasInternalBin)(fallbackCommand)) {
|
|
222
354
|
process.argv = [process.argv[0], process.argv[1], ...childArgs];
|
|
223
355
|
const loaded = await (0, _internalBinLoader.loadInternalBin)(fallbackCommand);
|
|
@@ -256,10 +388,20 @@ CommanderArgsCompat.prototype.argv = async function (argv, cb) {
|
|
|
256
388
|
const options = this.parse(parsedAlias.argv);
|
|
257
389
|
|
|
258
390
|
// If there's a sub-command, run that instead
|
|
259
|
-
|
|
260
|
-
|
|
391
|
+
const dispatchSubcommand = this.findSubcommand(parsedAlias.argv);
|
|
392
|
+
if (dispatchSubcommand) {
|
|
393
|
+
await this.executeSubcommand(argv, parsedAlias, dispatchSubcommand);
|
|
261
394
|
return {};
|
|
262
395
|
}
|
|
396
|
+
if (!_opts.wildcardCommand) {
|
|
397
|
+
const unknownOption = this.findUnknownOption(parsedAlias.argv);
|
|
398
|
+
if (unknownOption) {
|
|
399
|
+
await (0, _tracker.trackEvent)('command_validation_error', {
|
|
400
|
+
error: `Unknown option: ${unknownOption}`
|
|
401
|
+
});
|
|
402
|
+
exit.withError(`The option "${unknownOption}" is unknown. Did you mean the following one?\n-h, --help Retrieve a description, examples, and available options for a (sub)command.`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
263
405
|
if (_opts.format && !options.format) {
|
|
264
406
|
options.format = 'table';
|
|
265
407
|
}
|
|
@@ -267,11 +267,12 @@ function parseComponentForInfo(component) {
|
|
|
267
267
|
async function showLogs(lando, slug, options = {}) {
|
|
268
268
|
debug('Will display logs command on env', slug, 'with options', options);
|
|
269
269
|
const instancePath = getEnvironmentPath(slug);
|
|
270
|
-
debug('Instance path for', slug,
|
|
270
|
+
debug('Instance path for %s is %s', slug, instancePath);
|
|
271
271
|
if (options.service) {
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
272
|
+
const application = await (0, _devEnvironmentLando.getLandoApplication)(lando, instancePath);
|
|
273
|
+
const services = application.info.map(service => service.service);
|
|
274
|
+
if (!services.includes(options.service)) {
|
|
275
|
+
throw new _userError.default(`Service '${options.service}' not found. Please choose from: ${services.join(', ')}`);
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
return (0, _devEnvironmentLando.landoLogs)(lando, instancePath, options);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.bootstrapLando = bootstrapLando;
|
|
5
5
|
exports.checkEnvHealth = checkEnvHealth;
|
|
6
|
+
exports.getLandoApplication = getLandoApplication;
|
|
6
7
|
exports.getProxyContainer = getProxyContainer;
|
|
7
8
|
exports.isContainerRunning = isContainerRunning;
|
|
8
9
|
exports.isEnvUp = isEnvUp;
|