@automattic/vip 3.25.1 → 3.25.2-dev.0
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/AGENTS.md +6 -0
- package/CLAUDE.md +1 -0
- package/dist/bin/vip-dev-env-exec.js +18 -1
- package/dist/bin/vip-import.js +1 -1
- package/dist/bin/vip-sea.js +19 -0
- package/dist/bin/vip.js +111 -69
- package/dist/lib/cli/command.js +224 -53
- package/dist/lib/cli/config.js +13 -5
- package/dist/lib/cli/exit.js +2 -1
- package/dist/lib/cli/internal-bin-loader.js +81 -0
- package/dist/lib/cli/runtime-mode.js +21 -0
- package/dist/lib/cli/sea-dispatch.js +88 -0
- package/dist/lib/cli/sea-runtime.js +75 -0
- package/dist/lib/dev-environment/dev-environment-cli.js +9 -2
- package/dist/lib/dev-environment/dev-environment-core.js +62 -4
- package/dist/lib/dev-environment/dev-environment-lando.js +47 -10
- package/dist/lib/dev-environment/lando-loader.js +48 -0
- package/docs/COMMANDER-MIGRATION.md +55 -0
- package/docs/SEA-BUILD-SIGNING.md +171 -0
- package/helpers/build-sea.js +167 -0
- package/npm-shrinkwrap.json +499 -121
- package/package.json +6 -3
package/dist/lib/cli/config.js
CHANGED
|
@@ -4,8 +4,9 @@ exports.__esModule = true;
|
|
|
4
4
|
exports.default = void 0;
|
|
5
5
|
exports.loadConfigFile = loadConfigFile;
|
|
6
6
|
var _debug = _interopRequireDefault(require("debug"));
|
|
7
|
-
var _nodeFs = require("node:fs");
|
|
7
|
+
var _nodeFs = _interopRequireDefault(require("node:fs"));
|
|
8
8
|
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
9
|
+
var _configPublish = _interopRequireDefault(require("../../../config/config.publish.json"));
|
|
9
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
// I don't like using synchronous versions, but until we migrate to ESM, we have to.
|
|
11
12
|
|
|
@@ -14,26 +15,33 @@ function loadConfigFile() {
|
|
|
14
15
|
const paths = [
|
|
15
16
|
// Get `local` config first; this will only exist in dev as it's npmignore-d.
|
|
16
17
|
_nodePath.default.join(__dirname, '../../../config/config.local.json'), _nodePath.default.join(__dirname, '../../../config/config.publish.json')];
|
|
18
|
+
let hasNonEnoentError = false;
|
|
17
19
|
for (const filePath of paths) {
|
|
18
20
|
try {
|
|
19
|
-
const data =
|
|
21
|
+
const data = _nodeFs.default.readFileSync(filePath, 'utf-8');
|
|
20
22
|
debug(`Found config file at ${filePath}`);
|
|
21
23
|
return JSON.parse(data);
|
|
22
24
|
} catch (err) {
|
|
23
|
-
|
|
25
|
+
const isEnoent = err instanceof Error && 'code' in err && err.code === 'ENOENT';
|
|
26
|
+
if (!isEnoent) {
|
|
27
|
+
hasNonEnoentError = true;
|
|
24
28
|
debug(`Error reading config file at ${filePath}:`, err);
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
}
|
|
32
|
+
|
|
33
|
+
// SEA builds can miss on-disk config files, so use the bundled publish config only for ENOENT.
|
|
34
|
+
if (!hasNonEnoentError) {
|
|
35
|
+
return _configPublish.default;
|
|
36
|
+
}
|
|
28
37
|
return null;
|
|
29
38
|
}
|
|
30
39
|
const configFromFile = loadConfigFile();
|
|
31
40
|
if (null === configFromFile) {
|
|
32
|
-
// This should not happen because `config/config.publish.json` is always present.
|
|
33
41
|
console.error('FATAL ERROR: Could not find a valid configuration file');
|
|
34
42
|
process.exit(1);
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
// Without this, TypeScript will export `configFromFile` as `Config | null
|
|
45
|
+
// Without this, TypeScript will export `configFromFile` as `Config | null`.
|
|
38
46
|
const exportedConfig = configFromFile;
|
|
39
47
|
var _default = exports.default = exportedConfig;
|
package/dist/lib/cli/exit.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.__esModule = true;
|
|
|
4
4
|
exports.withError = withError;
|
|
5
5
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
6
6
|
var _debug = _interopRequireDefault(require("debug"));
|
|
7
|
+
var _runtimeMode = require("./runtime-mode");
|
|
7
8
|
var _env = _interopRequireDefault(require("../../lib/env"));
|
|
8
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
10
|
function withError(message) {
|
|
@@ -13,7 +14,7 @@ function withError(message) {
|
|
|
13
14
|
// Debug ouput is printed below error output both for information
|
|
14
15
|
// hierarchy and to make it more likely that the user copies it to their
|
|
15
16
|
// clipboard when dragging across output.
|
|
16
|
-
console.log(`${_chalk.default.yellow('Debug: ')} VIP-CLI v${_env.default.app.version}, Node ${_env.default.node.version}, ${_env.default.os.name} ${_env.default.os.version} ${_env.default.os.arch}`);
|
|
17
|
+
console.log(`${_chalk.default.yellow('Debug: ')} VIP-CLI v${_env.default.app.version}, Node ${_env.default.node.version}, ${_env.default.os.name} ${_env.default.os.version} ${_env.default.os.arch}, Runtime ${(0, _runtimeMode.getRuntimeModeLabel)()}`);
|
|
17
18
|
if (_debug.default.names.length > 0 && message instanceof Error) {
|
|
18
19
|
console.error(_chalk.default.yellow('Debug: '), message);
|
|
19
20
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.hasInternalBin = hasInternalBin;
|
|
5
|
+
exports.internalBinNames = void 0;
|
|
6
|
+
exports.loadInternalBin = loadInternalBin;
|
|
7
|
+
const internalBinLoaders = {
|
|
8
|
+
vip: () => import('../../bin/vip'),
|
|
9
|
+
'vip-app': () => import('../../bin/vip-app'),
|
|
10
|
+
'vip-app-deploy': () => import('../../bin/vip-app-deploy'),
|
|
11
|
+
'vip-app-deploy-validate': () => import('../../bin/vip-app-deploy-validate'),
|
|
12
|
+
'vip-app-list': () => import('../../bin/vip-app-list'),
|
|
13
|
+
'vip-backup': () => import('../../bin/vip-backup'),
|
|
14
|
+
'vip-backup-db': () => import('../../bin/vip-backup-db'),
|
|
15
|
+
'vip-cache': () => import('../../bin/vip-cache'),
|
|
16
|
+
'vip-cache-purge-url': () => import('../../bin/vip-cache-purge-url'),
|
|
17
|
+
'vip-config': () => import('../../bin/vip-config'),
|
|
18
|
+
'vip-config-envvar': () => import('../../bin/vip-config-envvar'),
|
|
19
|
+
'vip-config-envvar-delete': () => import('../../bin/vip-config-envvar-delete'),
|
|
20
|
+
'vip-config-envvar-get': () => import('../../bin/vip-config-envvar-get'),
|
|
21
|
+
'vip-config-envvar-get-all': () => import('../../bin/vip-config-envvar-get-all'),
|
|
22
|
+
'vip-config-envvar-list': () => import('../../bin/vip-config-envvar-list'),
|
|
23
|
+
'vip-config-envvar-set': () => import('../../bin/vip-config-envvar-set'),
|
|
24
|
+
'vip-config-software': () => import('../../bin/vip-config-software'),
|
|
25
|
+
'vip-config-software-get': () => import('../../bin/vip-config-software-get'),
|
|
26
|
+
'vip-config-software-update': () => import('../../bin/vip-config-software-update'),
|
|
27
|
+
'vip-db': () => import('../../bin/vip-db'),
|
|
28
|
+
'vip-db-phpmyadmin': () => import('../../bin/vip-db-phpmyadmin'),
|
|
29
|
+
'vip-dev-env': () => import('../../bin/vip-dev-env'),
|
|
30
|
+
'vip-dev-env-create': () => import('../../bin/vip-dev-env-create'),
|
|
31
|
+
'vip-dev-env-destroy': () => import('../../bin/vip-dev-env-destroy'),
|
|
32
|
+
'vip-dev-env-envvar': () => import('../../bin/vip-dev-env-envvar'),
|
|
33
|
+
'vip-dev-env-envvar-delete': () => import('../../bin/vip-dev-env-envvar-delete'),
|
|
34
|
+
'vip-dev-env-envvar-get': () => import('../../bin/vip-dev-env-envvar-get'),
|
|
35
|
+
'vip-dev-env-envvar-get-all': () => import('../../bin/vip-dev-env-envvar-get-all'),
|
|
36
|
+
'vip-dev-env-envvar-list': () => import('../../bin/vip-dev-env-envvar-list'),
|
|
37
|
+
'vip-dev-env-envvar-set': () => import('../../bin/vip-dev-env-envvar-set'),
|
|
38
|
+
'vip-dev-env-exec': () => import('../../bin/vip-dev-env-exec'),
|
|
39
|
+
'vip-dev-env-import': () => import('../../bin/vip-dev-env-import'),
|
|
40
|
+
'vip-dev-env-import-media': () => import('../../bin/vip-dev-env-import-media'),
|
|
41
|
+
'vip-dev-env-import-sql': () => import('../../bin/vip-dev-env-import-sql'),
|
|
42
|
+
'vip-dev-env-info': () => import('../../bin/vip-dev-env-info'),
|
|
43
|
+
'vip-dev-env-list': () => import('../../bin/vip-dev-env-list'),
|
|
44
|
+
'vip-dev-env-logs': () => import('../../bin/vip-dev-env-logs'),
|
|
45
|
+
'vip-dev-env-purge': () => import('../../bin/vip-dev-env-purge'),
|
|
46
|
+
'vip-dev-env-shell': () => import('../../bin/vip-dev-env-shell'),
|
|
47
|
+
'vip-dev-env-start': () => import('../../bin/vip-dev-env-start'),
|
|
48
|
+
'vip-dev-env-stop': () => import('../../bin/vip-dev-env-stop'),
|
|
49
|
+
'vip-dev-env-sync': () => import('../../bin/vip-dev-env-sync'),
|
|
50
|
+
'vip-dev-env-sync-sql': () => import('../../bin/vip-dev-env-sync-sql'),
|
|
51
|
+
'vip-dev-env-update': () => import('../../bin/vip-dev-env-update'),
|
|
52
|
+
'vip-export': () => import('../../bin/vip-export'),
|
|
53
|
+
'vip-export-sql': () => import('../../bin/vip-export-sql'),
|
|
54
|
+
'vip-import': () => import('../../bin/vip-import'),
|
|
55
|
+
'vip-import-media': () => import('../../bin/vip-import-media'),
|
|
56
|
+
'vip-import-media-abort': () => import('../../bin/vip-import-media-abort'),
|
|
57
|
+
'vip-import-media-status': () => import('../../bin/vip-import-media-status'),
|
|
58
|
+
'vip-import-sql': () => import('../../bin/vip-import-sql'),
|
|
59
|
+
'vip-import-sql-status': () => import('../../bin/vip-import-sql-status'),
|
|
60
|
+
'vip-import-validate-files': () => import('../../bin/vip-import-validate-files'),
|
|
61
|
+
'vip-import-validate-sql': () => import('../../bin/vip-import-validate-sql'),
|
|
62
|
+
'vip-logout': () => import('../../bin/vip-logout'),
|
|
63
|
+
'vip-logs': () => import('../../bin/vip-logs'),
|
|
64
|
+
'vip-search-replace': () => import('../../bin/vip-search-replace'),
|
|
65
|
+
'vip-slowlogs': () => import('../../bin/vip-slowlogs'),
|
|
66
|
+
'vip-sync': () => import('../../bin/vip-sync'),
|
|
67
|
+
'vip-whoami': () => import('../../bin/vip-whoami'),
|
|
68
|
+
'vip-wp': () => import('../../bin/vip-wp')
|
|
69
|
+
};
|
|
70
|
+
const internalBinNames = exports.internalBinNames = Object.freeze(Object.keys(internalBinLoaders));
|
|
71
|
+
async function loadInternalBin(binName) {
|
|
72
|
+
const loader = internalBinLoaders[binName];
|
|
73
|
+
if (!loader) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
await loader();
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
function hasInternalBin(binName) {
|
|
80
|
+
return Object.hasOwn(internalBinLoaders, binName);
|
|
81
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.getRuntimeModeLabel = getRuntimeModeLabel;
|
|
5
|
+
exports.isStandaloneExecutableRuntime = isStandaloneExecutableRuntime;
|
|
6
|
+
var _nodeModule = require("node:module");
|
|
7
|
+
const runtimeRequire = (0, _nodeModule.createRequire)(__filename);
|
|
8
|
+
function isStandaloneExecutableRuntime() {
|
|
9
|
+
if (process.env.VIP_CLI_SEA_MODE === '1') {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const sea = runtimeRequire('node:sea');
|
|
14
|
+
return Boolean(sea?.isSea?.());
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function getRuntimeModeLabel() {
|
|
20
|
+
return isStandaloneExecutableRuntime() ? 'standalone-sea' : 'node-script';
|
|
21
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.isSeaRuntime = isSeaRuntime;
|
|
5
|
+
exports.resolveInternalBinFromArgv = resolveInternalBinFromArgv;
|
|
6
|
+
exports.rewriteArgvForInternalBin = rewriteArgvForInternalBin;
|
|
7
|
+
var _envAlias = require("./envAlias");
|
|
8
|
+
var _internalBinLoader = require("./internal-bin-loader");
|
|
9
|
+
const internalBinSet = new Set(_internalBinLoader.internalBinNames);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the best matching internal bin for a command argv.
|
|
13
|
+
*
|
|
14
|
+
* @param {string[]} argv process.argv style array
|
|
15
|
+
* @returns {{ bin: string, start: number, length: number }}
|
|
16
|
+
*/
|
|
17
|
+
function resolveInternalBinFromArgv(argv) {
|
|
18
|
+
const args = argv.slice(2);
|
|
19
|
+
const dashDashIndex = args.indexOf('--');
|
|
20
|
+
const commandBoundary = dashDashIndex > -1 ? dashDashIndex : args.length;
|
|
21
|
+
let best = {
|
|
22
|
+
bin: 'vip',
|
|
23
|
+
start: 0,
|
|
24
|
+
length: 0
|
|
25
|
+
};
|
|
26
|
+
for (let start = 0; start < commandBoundary; start++) {
|
|
27
|
+
const firstToken = args[start];
|
|
28
|
+
if (!firstToken || firstToken.startsWith('-') || (0, _envAlias.isAlias)(firstToken)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const commandParts = [];
|
|
32
|
+
for (let index = start; index < commandBoundary; index++) {
|
|
33
|
+
const token = args[index];
|
|
34
|
+
if (!token || token.startsWith('-') || (0, _envAlias.isAlias)(token)) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
commandParts.push(token);
|
|
38
|
+
const candidateBin = `vip-${commandParts.join('-')}`;
|
|
39
|
+
if (internalBinSet.has(candidateBin)) {
|
|
40
|
+
const isLongerMatch = commandParts.length > best.length;
|
|
41
|
+
const isEarlierEqualMatch = commandParts.length === best.length && commandParts.length > 0 && start < best.start;
|
|
42
|
+
if (isLongerMatch || isEarlierEqualMatch) {
|
|
43
|
+
best = {
|
|
44
|
+
bin: candidateBin,
|
|
45
|
+
start,
|
|
46
|
+
length: commandParts.length
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return best;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Rewrites argv so the resolved command segment is removed and the target bin
|
|
57
|
+
* can parse its native flags/args shape.
|
|
58
|
+
*
|
|
59
|
+
* @param {string[]} argv process.argv style array
|
|
60
|
+
* @param {{ start: number, length: number }} resolution command resolution
|
|
61
|
+
* @returns {string[]} rewritten argv
|
|
62
|
+
*/
|
|
63
|
+
function rewriteArgvForInternalBin(argv, resolution) {
|
|
64
|
+
const args = argv.slice(2);
|
|
65
|
+
const start = resolution.start ?? 0;
|
|
66
|
+
const length = resolution.length ?? 0;
|
|
67
|
+
if (length <= 0) {
|
|
68
|
+
return argv.slice(0);
|
|
69
|
+
}
|
|
70
|
+
const rewrittenArgs = args.slice(0, start).concat(args.slice(start + length));
|
|
71
|
+
return [argv[0], argv[1], ...rewrittenArgs];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
function isSeaRuntime() {
|
|
78
|
+
try {
|
|
79
|
+
const runtimeRequire = typeof module !== 'undefined' && module?.require ? module.require.bind(module) : null;
|
|
80
|
+
if (!runtimeRequire) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const sea = runtimeRequire('node:sea');
|
|
84
|
+
return Boolean(sea?.isSea?.());
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.prepareSeaRuntimeFilesystem = prepareSeaRuntimeFilesystem;
|
|
5
|
+
var _nodeFs = require("node:fs");
|
|
6
|
+
var _promises = require("node:fs/promises");
|
|
7
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
8
|
+
var _package = _interopRequireDefault(require("../../../package.json"));
|
|
9
|
+
var _xdgData = require("../xdg-data");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
const RUNTIME_ARCHIVE_KEY = 'sea.node_modules.tgz';
|
|
12
|
+
const RUNTIME_DIR_NAME = 'sea-runtime';
|
|
13
|
+
const READY_FILE_NAME = '.ready';
|
|
14
|
+
const ARCHIVE_FILE_NAME = 'node_modules.tgz';
|
|
15
|
+
async function getSeaModule() {
|
|
16
|
+
try {
|
|
17
|
+
return await import('node:sea');
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function getRuntimeRootPath() {
|
|
23
|
+
return _nodePath.default.join((0, _xdgData.xdgData)(), 'vip', RUNTIME_DIR_NAME, _package.default.version);
|
|
24
|
+
}
|
|
25
|
+
function getRuntimeNodeModulesPath(runtimeRootPath) {
|
|
26
|
+
return _nodePath.default.join(runtimeRootPath, 'node_modules');
|
|
27
|
+
}
|
|
28
|
+
function getRuntimeReadyPath(runtimeRootPath) {
|
|
29
|
+
return _nodePath.default.join(runtimeRootPath, READY_FILE_NAME);
|
|
30
|
+
}
|
|
31
|
+
function appendNodePath(nodeModulesPath) {
|
|
32
|
+
const existing = process.env.NODE_PATH ? process.env.NODE_PATH.split(_nodePath.default.delimiter) : [];
|
|
33
|
+
if (!existing.includes(nodeModulesPath)) {
|
|
34
|
+
process.env.NODE_PATH = [nodeModulesPath, ...existing].join(_nodePath.default.delimiter);
|
|
35
|
+
}
|
|
36
|
+
const Module = require('node:module');
|
|
37
|
+
Module.Module._initPaths();
|
|
38
|
+
const runtimeEntryPath = _nodePath.default.join(nodeModulesPath, '..', '__sea-entry__.js');
|
|
39
|
+
const runtimeRequire = Module.createRequire(runtimeEntryPath);
|
|
40
|
+
module.filename = runtimeEntryPath;
|
|
41
|
+
module.paths = Module._nodeModulePaths(_nodePath.default.dirname(runtimeEntryPath));
|
|
42
|
+
module.require = runtimeRequire;
|
|
43
|
+
}
|
|
44
|
+
async function extractRuntimeDependencies(runtimeRootPath, archiveBuffer) {
|
|
45
|
+
await (0, _promises.rm)(runtimeRootPath, {
|
|
46
|
+
recursive: true,
|
|
47
|
+
force: true
|
|
48
|
+
});
|
|
49
|
+
await (0, _promises.mkdir)(runtimeRootPath, {
|
|
50
|
+
recursive: true
|
|
51
|
+
});
|
|
52
|
+
const archivePath = _nodePath.default.join(runtimeRootPath, ARCHIVE_FILE_NAME);
|
|
53
|
+
await (0, _promises.writeFile)(archivePath, archiveBuffer);
|
|
54
|
+
const tar = require('tar');
|
|
55
|
+
await tar.x({
|
|
56
|
+
file: archivePath,
|
|
57
|
+
cwd: runtimeRootPath
|
|
58
|
+
});
|
|
59
|
+
await (0, _promises.writeFile)(getRuntimeReadyPath(runtimeRootPath), _package.default.version, 'utf8');
|
|
60
|
+
}
|
|
61
|
+
async function prepareSeaRuntimeFilesystem() {
|
|
62
|
+
const sea = await getSeaModule();
|
|
63
|
+
if (!sea?.isSea?.() || !sea.getAsset) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const runtimeRootPath = getRuntimeRootPath();
|
|
67
|
+
const runtimeNodeModulesPath = getRuntimeNodeModulesPath(runtimeRootPath);
|
|
68
|
+
const runtimeReadyPath = getRuntimeReadyPath(runtimeRootPath);
|
|
69
|
+
if (!(0, _nodeFs.existsSync)(runtimeReadyPath) || !(0, _nodeFs.existsSync)(runtimeNodeModulesPath)) {
|
|
70
|
+
const archiveAsset = sea.getAsset(RUNTIME_ARCHIVE_KEY);
|
|
71
|
+
const archiveBuffer = Buffer.isBuffer(archiveAsset) ? archiveAsset : Buffer.from(archiveAsset);
|
|
72
|
+
await extractRuntimeDependencies(runtimeRootPath, archiveBuffer);
|
|
73
|
+
}
|
|
74
|
+
appendNodePath(runtimeNodeModulesPath);
|
|
75
|
+
}
|
|
@@ -38,7 +38,6 @@ var _chalk = _interopRequireDefault(require("chalk"));
|
|
|
38
38
|
var _child_process = require("child_process");
|
|
39
39
|
var _debug = _interopRequireDefault(require("debug"));
|
|
40
40
|
var _enquirer = require("enquirer");
|
|
41
|
-
var _formatters = _interopRequireDefault(require("lando/lib/formatters"));
|
|
42
41
|
var _nodeFs = require("node:fs");
|
|
43
42
|
var _nodeOs = require("node:os");
|
|
44
43
|
var _path = _interopRequireDefault(require("path"));
|
|
@@ -46,6 +45,7 @@ var _shelljs = require("shelljs");
|
|
|
46
45
|
var _devEnvironmentConfigurationFile = require("./dev-environment-configuration-file");
|
|
47
46
|
var _devEnvironmentCore = require("./dev-environment-core");
|
|
48
47
|
var _devEnvironmentLando = require("./dev-environment-lando");
|
|
48
|
+
var _landoLoader = require("./lando-loader");
|
|
49
49
|
var _user = require("../api/user");
|
|
50
50
|
var _devEnvironment = require("../constants/dev-environment");
|
|
51
51
|
var _tracker = require("../tracker");
|
|
@@ -55,6 +55,13 @@ const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
|
|
|
55
55
|
const DEFAULT_SLUG = exports.DEFAULT_SLUG = 'vip-local';
|
|
56
56
|
const CONFIGURATION_FOLDER = exports.CONFIGURATION_FOLDER = '.wpvip';
|
|
57
57
|
let isStdinTTY = Boolean(process.stdin.isTTY);
|
|
58
|
+
let landoFormatters = null;
|
|
59
|
+
const getLandoFormatters = () => {
|
|
60
|
+
if (!landoFormatters) {
|
|
61
|
+
landoFormatters = (0, _landoLoader.loadLandoModule)('lando/lib/formatters');
|
|
62
|
+
}
|
|
63
|
+
return landoFormatters;
|
|
64
|
+
};
|
|
58
65
|
|
|
59
66
|
/**
|
|
60
67
|
* Used internally for tests
|
|
@@ -150,7 +157,7 @@ function getEnvironmentStartCommand(slug, configurationFileOptions) {
|
|
|
150
157
|
return `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} start --slug ${slug}`;
|
|
151
158
|
}
|
|
152
159
|
function printTable(data) {
|
|
153
|
-
const formattedData =
|
|
160
|
+
const formattedData = getLandoFormatters().formatData(data, {
|
|
154
161
|
format: 'table'
|
|
155
162
|
}, {
|
|
156
163
|
border: false
|
|
@@ -28,7 +28,6 @@ var _debug = _interopRequireDefault(require("debug"));
|
|
|
28
28
|
var _ejs = _interopRequireDefault(require("ejs"));
|
|
29
29
|
var _enquirer = require("enquirer");
|
|
30
30
|
var _graphql = require("graphql");
|
|
31
|
-
var _utils = require("lando/lib/utils");
|
|
32
31
|
var _nodeFetch = _interopRequireDefault(require("node-fetch"));
|
|
33
32
|
var _nodeCrypto = require("node:crypto");
|
|
34
33
|
var _nodeFs = _interopRequireDefault(require("node:fs"));
|
|
@@ -37,6 +36,7 @@ var _nodePath = _interopRequireDefault(require("node:path"));
|
|
|
37
36
|
var _semver = _interopRequireDefault(require("semver"));
|
|
38
37
|
var _devEnvironmentCli = require("./dev-environment-cli");
|
|
39
38
|
var _devEnvironmentLando = require("./dev-environment-lando");
|
|
39
|
+
var _landoLoader = require("./lando-loader");
|
|
40
40
|
var _app = _interopRequireDefault(require("../api/app"));
|
|
41
41
|
var _software = require("../config/software");
|
|
42
42
|
var _devEnvironment = require("../constants/dev-environment");
|
|
@@ -47,7 +47,9 @@ var _xdgData = require("../xdg-data");
|
|
|
47
47
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
48
48
|
const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
|
|
49
49
|
const landoFileTemplatePath = _nodePath.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.lando.template.yml.ejs');
|
|
50
|
+
const landoTemplateAssetKey = 'dev-env.lando.template.yml.ejs';
|
|
50
51
|
const nginxFileTemplatePath = _nodePath.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.nginx.template.conf.ejs');
|
|
52
|
+
const nginxTemplateAssetKey = 'dev-env.nginx.template.conf.ejs';
|
|
51
53
|
const landoFileName = '.lando.yml';
|
|
52
54
|
const landoOverridesFileName = '.lando.local.yml';
|
|
53
55
|
const landoBackupFileName = '.lando.backup.yml';
|
|
@@ -58,6 +60,53 @@ const integrationsConfigBackupFileName = 'integrations.json.bak';
|
|
|
58
60
|
const uploadPathString = 'uploads';
|
|
59
61
|
const nginxPathString = 'nginx';
|
|
60
62
|
const integrationsConfigPathString = 'integrations-config';
|
|
63
|
+
const STARTUP_READY_ATTEMPTS = 6;
|
|
64
|
+
const STARTUP_READY_DELAY_MS = 2000;
|
|
65
|
+
let dockerComposifyFromLando = null;
|
|
66
|
+
const dockerComposify = value => {
|
|
67
|
+
if (!dockerComposifyFromLando) {
|
|
68
|
+
const landoUtils = (0, _landoLoader.loadLandoModule)('lando/lib/utils');
|
|
69
|
+
dockerComposifyFromLando = landoUtils.dockerComposify;
|
|
70
|
+
}
|
|
71
|
+
return dockerComposifyFromLando(value);
|
|
72
|
+
};
|
|
73
|
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
74
|
+
let seaModulePromise = null;
|
|
75
|
+
const getSeaModule = async () => {
|
|
76
|
+
if (!seaModulePromise) {
|
|
77
|
+
seaModulePromise = (async () => {
|
|
78
|
+
try {
|
|
79
|
+
return await import('node:sea');
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
84
|
+
}
|
|
85
|
+
return seaModulePromise;
|
|
86
|
+
};
|
|
87
|
+
const renderTemplateFile = async (filePath, assetKey, templateData) => {
|
|
88
|
+
const sea = await getSeaModule();
|
|
89
|
+
if (sea?.isSea?.() && sea.getAsset) {
|
|
90
|
+
const template = sea.getAsset(assetKey, 'utf8');
|
|
91
|
+
if (typeof template === 'string') {
|
|
92
|
+
return _ejs.default.render(template, templateData);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return _ejs.default.renderFile(filePath, templateData);
|
|
96
|
+
};
|
|
97
|
+
async function waitForEnvironmentToBeUp(lando, instancePath) {
|
|
98
|
+
return pollEnvironmentUpStatus(lando, instancePath, 1);
|
|
99
|
+
}
|
|
100
|
+
async function pollEnvironmentUpStatus(lando, instancePath, attempt) {
|
|
101
|
+
if (await (0, _devEnvironmentLando.isEnvUp)(lando, instancePath)) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
if (attempt >= STARTUP_READY_ATTEMPTS) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
await sleep(STARTUP_READY_DELAY_MS);
|
|
108
|
+
return pollEnvironmentUpStatus(lando, instancePath, attempt + 1);
|
|
109
|
+
}
|
|
61
110
|
async function startEnvironment(lando, slug, options) {
|
|
62
111
|
debug('Will start an environment', slug);
|
|
63
112
|
const instancePath = getEnvironmentPath(slug);
|
|
@@ -82,6 +131,15 @@ async function startEnvironment(lando, slug, options) {
|
|
|
82
131
|
} else {
|
|
83
132
|
await (0, _devEnvironmentLando.landoRebuild)(lando, instancePath);
|
|
84
133
|
}
|
|
134
|
+
let isEnvironmentUp = await waitForEnvironmentToBeUp(lando, instancePath);
|
|
135
|
+
if (!isEnvironmentUp) {
|
|
136
|
+
// A second startup pass helps recover after Docker network auto-cleanup edge cases.
|
|
137
|
+
await (0, _devEnvironmentLando.landoStart)(lando, instancePath);
|
|
138
|
+
isEnvironmentUp = await waitForEnvironmentToBeUp(lando, instancePath);
|
|
139
|
+
}
|
|
140
|
+
if (!isEnvironmentUp) {
|
|
141
|
+
throw new _userError.default(`Environment "${slug}" did not reach a running state. Please try "${_chalk.default.bold(`vip dev-env start --slug ${slug}`)}" again.`);
|
|
142
|
+
}
|
|
85
143
|
await printEnvironmentInfo(lando, slug, {
|
|
86
144
|
extended: false
|
|
87
145
|
});
|
|
@@ -166,7 +224,7 @@ async function destroyEnvironment(lando, slug, removeFiles) {
|
|
|
166
224
|
} else {
|
|
167
225
|
debug("Lando file doesn't exist, skipping lando destroy.");
|
|
168
226
|
}
|
|
169
|
-
await _nodeFs.default.promises.rm(_nodePath.default.join((0, _xdgData.xdgData)(), 'vip', 'lando', 'compose',
|
|
227
|
+
await _nodeFs.default.promises.rm(_nodePath.default.join((0, _xdgData.xdgData)(), 'vip', 'lando', 'compose', dockerComposify(slug)), {
|
|
170
228
|
force: true,
|
|
171
229
|
recursive: true
|
|
172
230
|
});
|
|
@@ -349,8 +407,8 @@ async function prepareLandoEnv(lando, instanceData, instancePath, integrationsCo
|
|
|
349
407
|
...instanceData,
|
|
350
408
|
domain: lando.config.domain
|
|
351
409
|
};
|
|
352
|
-
const landoFile = await
|
|
353
|
-
const nginxFile = await
|
|
410
|
+
const landoFile = await renderTemplateFile(landoFileTemplatePath, landoTemplateAssetKey, templateData);
|
|
411
|
+
const nginxFile = await renderTemplateFile(nginxFileTemplatePath, nginxTemplateAssetKey, templateData);
|
|
354
412
|
const instanceDataFile = JSON.stringify(instanceData);
|
|
355
413
|
const landoFileTargetPath = _nodePath.default.join(instancePath, landoFileName);
|
|
356
414
|
const landoOverridesFileTargetPath = _nodePath.default.join(instancePath, landoOverridesFileName);
|
|
@@ -18,10 +18,6 @@ exports.removeProxyCache = removeProxyCache;
|
|
|
18
18
|
exports.validateDockerInstalled = validateDockerInstalled;
|
|
19
19
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
20
20
|
var _debug = _interopRequireDefault(require("debug"));
|
|
21
|
-
var _bootstrap = require("lando/lib/bootstrap");
|
|
22
|
-
var _lando = _interopRequireDefault(require("lando/lib/lando"));
|
|
23
|
-
var _utils = _interopRequireDefault(require("lando/plugins/lando-core/lib/utils"));
|
|
24
|
-
var _build = _interopRequireDefault(require("lando/plugins/lando-tooling/lib/build"));
|
|
25
21
|
var _nodeChild_process = require("node:child_process");
|
|
26
22
|
var _promises = require("node:dns/promises");
|
|
27
23
|
var _promises2 = require("node:fs/promises");
|
|
@@ -31,6 +27,8 @@ var _nodeUtil = require("node:util");
|
|
|
31
27
|
var _semver = require("semver");
|
|
32
28
|
var _devEnvironmentCore = require("./dev-environment-core");
|
|
33
29
|
var _dockerUtils = require("./docker-utils");
|
|
30
|
+
var _landoLoader = require("./lando-loader");
|
|
31
|
+
var _runtimeMode = require("../cli/runtime-mode");
|
|
34
32
|
var _devEnvironment = require("../constants/dev-environment");
|
|
35
33
|
var _env = _interopRequireDefault(require("../env"));
|
|
36
34
|
var _userError = _interopRequireDefault(require("../user-error"));
|
|
@@ -43,6 +41,44 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
43
41
|
const DEBUG_KEY = '@automattic/vip:bin:dev-environment';
|
|
44
42
|
const debug = (0, _debug.default)(DEBUG_KEY);
|
|
45
43
|
const execFileAsync = (0, _nodeUtil.promisify)(_nodeChild_process.execFile);
|
|
44
|
+
const unwrapLandoModuleDefault = loaded => {
|
|
45
|
+
if (loaded && typeof loaded === 'object' && 'default' in loaded) {
|
|
46
|
+
return loaded.default;
|
|
47
|
+
}
|
|
48
|
+
return loaded;
|
|
49
|
+
};
|
|
50
|
+
let landoConstructor = null;
|
|
51
|
+
let landoBuildTaskFn = null;
|
|
52
|
+
let landoUtilsModule = null;
|
|
53
|
+
let buildConfigFn = null;
|
|
54
|
+
const getLandoConstructor = () => {
|
|
55
|
+
if (!landoConstructor) {
|
|
56
|
+
landoConstructor = unwrapLandoModuleDefault((0, _landoLoader.loadLandoModule)('lando/lib/lando'));
|
|
57
|
+
}
|
|
58
|
+
return landoConstructor;
|
|
59
|
+
};
|
|
60
|
+
const getLandoBuildTask = () => {
|
|
61
|
+
if (!landoBuildTaskFn) {
|
|
62
|
+
landoBuildTaskFn = unwrapLandoModuleDefault((0, _landoLoader.loadLandoModule)('lando/plugins/lando-tooling/lib/build'));
|
|
63
|
+
}
|
|
64
|
+
return landoBuildTaskFn;
|
|
65
|
+
};
|
|
66
|
+
const getLandoUtils = () => {
|
|
67
|
+
if (!landoUtilsModule) {
|
|
68
|
+
landoUtilsModule = unwrapLandoModuleDefault((0, _landoLoader.loadLandoModule)('lando/plugins/lando-core/lib/utils'));
|
|
69
|
+
}
|
|
70
|
+
return landoUtilsModule;
|
|
71
|
+
};
|
|
72
|
+
const getLandoBuildConfig = () => {
|
|
73
|
+
if (!buildConfigFn) {
|
|
74
|
+
const loaded = (0, _landoLoader.loadLandoModule)('lando/lib/bootstrap');
|
|
75
|
+
buildConfigFn = loaded.buildConfig ?? loaded.default?.buildConfig ?? null;
|
|
76
|
+
if (!buildConfigFn) {
|
|
77
|
+
throw new Error('Unable to load Lando bootstrap buildConfig.');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return buildConfigFn;
|
|
81
|
+
};
|
|
46
82
|
const bannerLabelWidth = 18;
|
|
47
83
|
let logPathRegistered = false;
|
|
48
84
|
let resolvedLogPath = null;
|
|
@@ -146,7 +182,7 @@ const writeLogBanner = async config => {
|
|
|
146
182
|
});
|
|
147
183
|
const dockerVersions = await getDockerVersions(config);
|
|
148
184
|
const command = process.argv.slice(1).join(' ');
|
|
149
|
-
const bannerLines = ['=== VIP Dev Env Log ===', formatBannerLine('COMMAND', command), formatBannerLine('OS', `${_env.default.os.name} ${_env.default.os.version} ${_env.default.os.arch}`), formatBannerLine('NODE', _env.default.node.version), formatBannerLine('VIP-CLI', _env.default.app.version), formatBannerLine('DOCKER ENGINE', dockerVersions.engine), formatBannerLine('DOCKER COMPOSE', dockerVersions.compose), formatBannerLine('COMPOSE PLUGIN', dockerVersions.composePlugin), formatBannerLine('DOCKER BIN', config.dockerBin ?? 'unknown'), formatBannerLine('COMPOSE BIN', config.composeBin ?? 'unknown'), formatBannerLine('RAM', formatBytes((0, _nodeOs.totalmem)())), formatBannerLine('CPU', String((0, _nodeOs.cpus)().length)), '===', '', ''];
|
|
185
|
+
const bannerLines = ['=== VIP Dev Env Log ===', formatBannerLine('COMMAND', command), formatBannerLine('OS', `${_env.default.os.name} ${_env.default.os.version} ${_env.default.os.arch}`), formatBannerLine('NODE', _env.default.node.version), formatBannerLine('VIP-CLI', _env.default.app.version), formatBannerLine('RUNTIME', (0, _runtimeMode.getRuntimeModeLabel)()), formatBannerLine('DOCKER ENGINE', dockerVersions.engine), formatBannerLine('DOCKER COMPOSE', dockerVersions.compose), formatBannerLine('COMPOSE PLUGIN', dockerVersions.composePlugin), formatBannerLine('DOCKER BIN', config.dockerBin ?? 'unknown'), formatBannerLine('COMPOSE BIN', config.composeBin ?? 'unknown'), formatBannerLine('RAM', formatBytes((0, _nodeOs.totalmem)())), formatBannerLine('CPU', String((0, _nodeOs.cpus)().length)), '===', '', ''];
|
|
150
186
|
await (0, _promises2.writeFile)(logFilePath, bannerLines.join('\n'), {
|
|
151
187
|
flag: 'a'
|
|
152
188
|
});
|
|
@@ -157,7 +193,7 @@ const writeLogBanner = async config => {
|
|
|
157
193
|
*/
|
|
158
194
|
async function getLandoConfig(options = {}) {
|
|
159
195
|
// The path will be smth like `yarn/global/node_modules/lando/lib/lando.js`; we need the path up to `lando` (inclusive)
|
|
160
|
-
const landoPath = (0, _nodePath.dirname)((0, _nodePath.dirname)(
|
|
196
|
+
const landoPath = (0, _nodePath.dirname)((0, _nodePath.dirname)((0, _landoLoader.resolveLandoModule)('lando')));
|
|
161
197
|
debug(`Getting Lando config, using paths '${landoPath}' for plugins`);
|
|
162
198
|
const isLandoDebugSelected = _debug.default.enabled(DEBUG_KEY);
|
|
163
199
|
const isAllDebugSelected = _debug.default.enabled('"*"');
|
|
@@ -201,7 +237,7 @@ async function getLandoConfig(options = {}) {
|
|
|
201
237
|
LANDO_HOST_GROUP_ID: process.platform === 'win32' ? '1000' : `${(0, _nodeOs.userInfo)().gid}`
|
|
202
238
|
}
|
|
203
239
|
};
|
|
204
|
-
return (
|
|
240
|
+
return getLandoBuildConfig()(config);
|
|
205
241
|
}
|
|
206
242
|
const appMap = new Map();
|
|
207
243
|
async function initLandoApplication(lando, instancePath) {
|
|
@@ -290,7 +326,8 @@ async function bootstrapLando(options = {}) {
|
|
|
290
326
|
}
|
|
291
327
|
registerLogPathOutput(config, Boolean(options.quiet));
|
|
292
328
|
await writeLogBanner(config);
|
|
293
|
-
const
|
|
329
|
+
const LandoClass = getLandoConstructor();
|
|
330
|
+
const lando = new LandoClass(config);
|
|
294
331
|
_debug.default.log = (message, ...args) => {
|
|
295
332
|
lando.log.debug(message, ...args);
|
|
296
333
|
};
|
|
@@ -425,7 +462,7 @@ async function landoInfo(lando, instancePath, options = {}) {
|
|
|
425
462
|
const started = new Date();
|
|
426
463
|
try {
|
|
427
464
|
const app = await getLandoApplication(lando, instancePath);
|
|
428
|
-
const info =
|
|
465
|
+
const info = getLandoUtils().startTable(app);
|
|
429
466
|
const reachableServices = app.info.filter(service => service.urls.length);
|
|
430
467
|
reachableServices.forEach(service => info[`${service.service} urls`] = service.urls);
|
|
431
468
|
const health = await checkEnvHealth(lando, app);
|
|
@@ -638,7 +675,7 @@ async function landoExec(lando, instancePath, toolName, args, options) {
|
|
|
638
675
|
if (options.stdio) {
|
|
639
676
|
tool.stdio = options.stdio;
|
|
640
677
|
}
|
|
641
|
-
const task = (
|
|
678
|
+
const task = getLandoBuildTask()(tool, lando);
|
|
642
679
|
const argv = {
|
|
643
680
|
// eslint-disable-next-line id-length
|
|
644
681
|
_: args
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.loadLandoModule = loadLandoModule;
|
|
5
|
+
exports.resolveLandoModule = resolveLandoModule;
|
|
6
|
+
var _nodeFs = require("node:fs");
|
|
7
|
+
var _nodeModule = require("node:module");
|
|
8
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
9
|
+
var _package = _interopRequireDefault(require("../../../package.json"));
|
|
10
|
+
var _xdgData = require("../xdg-data");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
const SEA_RUNTIME_DIR_NAME = 'sea-runtime';
|
|
13
|
+
let cachedRequire = null;
|
|
14
|
+
let didResolveRequire = false;
|
|
15
|
+
const baseRequire = (0, _nodeModule.createRequire)(__filename);
|
|
16
|
+
function isSeaRuntime() {
|
|
17
|
+
try {
|
|
18
|
+
const sea = baseRequire('node:sea');
|
|
19
|
+
return Boolean(sea?.isSea?.());
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function getSeaRuntimeNodeModulesPath() {
|
|
25
|
+
return _nodePath.default.join((0, _xdgData.xdgData)(), 'vip', SEA_RUNTIME_DIR_NAME, _package.default.version, 'node_modules');
|
|
26
|
+
}
|
|
27
|
+
function getRuntimeRequire() {
|
|
28
|
+
if (didResolveRequire && cachedRequire) {
|
|
29
|
+
return cachedRequire;
|
|
30
|
+
}
|
|
31
|
+
didResolveRequire = true;
|
|
32
|
+
if (isSeaRuntime()) {
|
|
33
|
+
const runtimeNodeModulesPath = getSeaRuntimeNodeModulesPath();
|
|
34
|
+
if ((0, _nodeFs.existsSync)(runtimeNodeModulesPath)) {
|
|
35
|
+
const runtimeEntryPath = _nodePath.default.join(runtimeNodeModulesPath, '..', '__sea-entry__.js');
|
|
36
|
+
cachedRequire = (0, _nodeModule.createRequire)(runtimeEntryPath);
|
|
37
|
+
return cachedRequire;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
cachedRequire = baseRequire;
|
|
41
|
+
return cachedRequire;
|
|
42
|
+
}
|
|
43
|
+
function loadLandoModule(request) {
|
|
44
|
+
return getRuntimeRequire()(request);
|
|
45
|
+
}
|
|
46
|
+
function resolveLandoModule(request) {
|
|
47
|
+
return getRuntimeRequire().resolve(request);
|
|
48
|
+
}
|