@wordpress/env 10.38.1-next.v.0 → 11.0.1-next.v.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/README.md +57 -5
- package/lib/cli.js +31 -21
- package/lib/commands/clean.js +6 -37
- package/lib/commands/destroy.js +5 -25
- package/lib/commands/index.js +2 -2
- package/lib/commands/logs.js +6 -57
- package/lib/commands/run.js +5 -110
- package/lib/commands/start.js +35 -240
- package/lib/commands/status.js +154 -0
- package/lib/commands/stop.js +6 -15
- package/lib/download-sources.js +9 -53
- package/lib/{build-docker-compose-config.js → runtime/docker/build-docker-compose-config.js} +3 -3
- package/lib/runtime/docker/download-sources.js +59 -0
- package/lib/runtime/docker/index.js +741 -0
- package/lib/{init-config.js → runtime/docker/init-config.js} +2 -2
- package/lib/runtime/docker/wordpress.js +324 -0
- package/lib/runtime/errors.js +17 -0
- package/lib/runtime/index.js +69 -0
- package/lib/runtime/playground/blueprint-builder.js +166 -0
- package/lib/runtime/playground/index.js +502 -0
- package/lib/test/build-docker-compose-config.js +3 -3
- package/lib/wordpress.js +1 -297
- package/package.json +6 -3
- package/lib/commands/install-path.js +0 -21
- package/lib/{download-wp-phpunit.js → runtime/docker/download-wp-phpunit.js} +1 -1
- /package/lib/{get-host-user.js → runtime/docker/get-host-user.js} +0 -0
- /package/lib/{validate-run-container.js → runtime/docker/validate-run-container.js} +0 -0
package/README.md
CHANGED
|
@@ -20,10 +20,39 @@ The database credentials are: user `root`, password `password`. For a comprehens
|
|
|
20
20
|
|
|
21
21
|
`wp-env` relies on a few commonly used developer tools:
|
|
22
22
|
|
|
23
|
-
- **Docker**. `wp-env` is powered by Docker. There are instructions available for installing Docker on [Windows](https://docs.docker.com/desktop/install/windows-install/) (we recommend the WSL2 backend), [macOS](https://docs.docker.com/docker-for-mac/install/), and [Linux](https://docs.docker.com/desktop/install/linux-install/).
|
|
23
|
+
- **Docker**. `wp-env` is powered by Docker by default. There are instructions available for installing Docker on [Windows](https://docs.docker.com/desktop/install/windows-install/) (we recommend the WSL2 backend), [macOS](https://docs.docker.com/docker-for-mac/install/), and [Linux](https://docs.docker.com/desktop/install/linux-install/).
|
|
24
24
|
- **Node.js**. `wp-env` is written as a Node script. We recommend using a Node version manager like [nvm](https://github.com/nvm-sh/nvm) to install the latest LTS version. Alternatively, you can [download it directly here](https://nodejs.org/en/download).
|
|
25
25
|
- **git**. Git is used for downloading software from source control, such as WordPress, plugins, and themes. [You can find the installation instructions here.](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
|
26
26
|
|
|
27
|
+
## Experimental: WordPress Playground Runtime
|
|
28
|
+
|
|
29
|
+
`wp-env` now supports an experimental alternative runtime using [WordPress Playground](https://wordpress.github.io/wordpress-playground/). Playground runs WordPress entirely in WebAssembly, eliminating the need for Docker.
|
|
30
|
+
|
|
31
|
+
To use the Playground runtime:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
$ wp-env start --runtime=playground
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Playground vs Docker
|
|
38
|
+
|
|
39
|
+
| Feature | Docker | Playground |
|
|
40
|
+
|---------|--------|------------|
|
|
41
|
+
| Requires Docker | Yes | No |
|
|
42
|
+
| Test environment | Yes | No |
|
|
43
|
+
| Xdebug | Yes | Yes |
|
|
44
|
+
| SPX profiling | Yes | No |
|
|
45
|
+
| phpMyAdmin | Yes | No |
|
|
46
|
+
| MySQL database | Yes | No (SQLite) |
|
|
47
|
+
| Multisite | Yes | Yes |
|
|
48
|
+
| Custom PHP version | Yes | Yes |
|
|
49
|
+
| Plugin/theme mounting | Yes | Yes |
|
|
50
|
+
| `wp-env run` command | Yes | No |
|
|
51
|
+
|
|
52
|
+
The Playground runtime is ideal for quick testing or environments where Docker is unavailable. However, it lacks some features available in the Docker runtime, such as the tests environment and the `run` command for executing arbitrary commands.
|
|
53
|
+
|
|
54
|
+
Once started with a runtime, wp-env will automatically detect and use the same runtime for subsequent commands (`stop`, `destroy`, etc.) until the environment is destroyed.
|
|
55
|
+
|
|
27
56
|
## Installation
|
|
28
57
|
|
|
29
58
|
### Installation as a global package
|
|
@@ -284,6 +313,9 @@ Options:
|
|
|
284
313
|
--debug Enable debug output. [boolean] [default: false]
|
|
285
314
|
--update Download source updates and apply WordPress configuration.
|
|
286
315
|
[boolean] [default: false]
|
|
316
|
+
--runtime Select the runtime to use. "docker" uses Docker containers,
|
|
317
|
+
"playground" uses WordPress Playground (experimental).
|
|
318
|
+
[string] [choices: "docker", "playground"]
|
|
287
319
|
--xdebug Enables Xdebug. If not passed, Xdebug is turned off. If no modes
|
|
288
320
|
are set, uses "debug". You may set multiple Xdebug modes by passing
|
|
289
321
|
them in a comma-separated list: `--xdebug=develop,coverage`. See
|
|
@@ -466,16 +498,36 @@ Options:
|
|
|
466
498
|
--watch Watch for logs as they happen. [boolean] [default: true]
|
|
467
499
|
```
|
|
468
500
|
|
|
469
|
-
### `wp-env
|
|
501
|
+
### `wp-env status`
|
|
470
502
|
|
|
471
|
-
Get the
|
|
503
|
+
Get the status of the wp-env environment including whether it's running, URLs, ports, and configuration.
|
|
472
504
|
|
|
473
505
|
Example:
|
|
474
506
|
|
|
475
507
|
```sh
|
|
476
|
-
$ wp-env
|
|
508
|
+
$ wp-env status
|
|
509
|
+
|
|
510
|
+
status: running
|
|
511
|
+
- runtime: docker
|
|
512
|
+
- install path: /home/user/.wp-env/63263e6506becb7b8613b02d42280a49
|
|
513
|
+
- config: /home/user/my-plugin
|
|
514
|
+
|
|
515
|
+
environment:
|
|
516
|
+
- url: http://localhost:8888
|
|
517
|
+
- multisite: no
|
|
518
|
+
- xdebug: off
|
|
519
|
+
- http port: 8888
|
|
520
|
+
- mysql port: 13306
|
|
521
|
+
- test http port: 8889
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
```sh
|
|
525
|
+
$ wp-env status --help
|
|
526
|
+
Get the status of the wp-env environment including URLs, ports, and configuration.
|
|
477
527
|
|
|
478
|
-
|
|
528
|
+
Options:
|
|
529
|
+
--debug Enable debug output. [boolean] [default: false]
|
|
530
|
+
--json Output status as JSON. [boolean] [default: false]
|
|
479
531
|
```
|
|
480
532
|
|
|
481
533
|
## .wp-env.json
|
package/lib/cli.js
CHANGED
|
@@ -6,7 +6,6 @@ const chalk = require( 'chalk' );
|
|
|
6
6
|
const ora = require( 'ora' );
|
|
7
7
|
const yargs = require( 'yargs' );
|
|
8
8
|
const terminalLink = require( 'terminal-link' );
|
|
9
|
-
const { execSync } = require( 'child_process' );
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Internal dependencies
|
|
@@ -16,9 +15,10 @@ const env = require( './env' );
|
|
|
16
15
|
const parseXdebugMode = require( './parse-xdebug-mode' );
|
|
17
16
|
const parseSpxMode = require( './parse-spx-mode' );
|
|
18
17
|
const {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
getAvailableRuntimes,
|
|
19
|
+
getRuntime,
|
|
20
|
+
UnsupportedCommandError,
|
|
21
|
+
} = require( './runtime' );
|
|
22
22
|
|
|
23
23
|
// Colors.
|
|
24
24
|
const boldWhite = chalk.bold.white;
|
|
@@ -45,7 +45,11 @@ const withSpinner =
|
|
|
45
45
|
process.exit( 0 );
|
|
46
46
|
},
|
|
47
47
|
( error ) => {
|
|
48
|
-
if (
|
|
48
|
+
if ( error instanceof UnsupportedCommandError ) {
|
|
49
|
+
// Error is an unsupported command in the current runtime.
|
|
50
|
+
spinner.fail( error.message );
|
|
51
|
+
process.exit( 1 );
|
|
52
|
+
} else if (
|
|
49
53
|
error instanceof env.ValidationError ||
|
|
50
54
|
error instanceof env.LifecycleScriptError
|
|
51
55
|
) {
|
|
@@ -87,16 +91,6 @@ const withSpinner =
|
|
|
87
91
|
};
|
|
88
92
|
|
|
89
93
|
module.exports = function cli() {
|
|
90
|
-
// Do nothing if Docker is unavailable.
|
|
91
|
-
try {
|
|
92
|
-
execSync( 'docker info', { stdio: 'ignore' } );
|
|
93
|
-
} catch {
|
|
94
|
-
console.error(
|
|
95
|
-
chalk.red( 'Could not connect to Docker. Is it running?' )
|
|
96
|
-
);
|
|
97
|
-
process.exit( 1 );
|
|
98
|
-
}
|
|
99
|
-
|
|
100
94
|
yargs.usage( wpPrimary( '$0 <command>' ) );
|
|
101
95
|
yargs.option( 'debug', {
|
|
102
96
|
type: 'boolean',
|
|
@@ -150,6 +144,13 @@ module.exports = function cli() {
|
|
|
150
144
|
describe: 'Execute any configured lifecycle scripts.',
|
|
151
145
|
default: true,
|
|
152
146
|
} );
|
|
147
|
+
args.option( 'runtime', {
|
|
148
|
+
type: 'string',
|
|
149
|
+
describe:
|
|
150
|
+
'The runtime environment to use. "docker" uses Docker containers, "playground" uses WordPress Playground (experimental).',
|
|
151
|
+
choices: getAvailableRuntimes(),
|
|
152
|
+
default: 'docker',
|
|
153
|
+
} );
|
|
153
154
|
},
|
|
154
155
|
withSpinner( env.start )
|
|
155
156
|
);
|
|
@@ -201,6 +202,10 @@ module.exports = function cli() {
|
|
|
201
202
|
'$0 logs --no-watch --environment=tests',
|
|
202
203
|
'Displays the latest logs for the e2e test environment without watching.'
|
|
203
204
|
);
|
|
205
|
+
// Get run containers from Docker runtime (run command is Docker-only for now)
|
|
206
|
+
const dockerRuntime = getRuntime( 'docker' );
|
|
207
|
+
const runContainers = dockerRuntime.getRunContainers();
|
|
208
|
+
|
|
204
209
|
yargs.command(
|
|
205
210
|
'run <container> [command...]',
|
|
206
211
|
'Runs an arbitrary command in one of the underlying Docker containers. A double dash can be used to pass arguments to the container without parsing them. This is necessary if you are using an option that is defined below. You can use `bash` to open a shell session and both `composer` and `phpunit` are available in all WordPress and CLI containers. WP-CLI is also available in the CLI containers.',
|
|
@@ -216,8 +221,7 @@ module.exports = function cli() {
|
|
|
216
221
|
type: 'string',
|
|
217
222
|
describe:
|
|
218
223
|
'The underlying Docker service to run the command on.',
|
|
219
|
-
choices:
|
|
220
|
-
coerce: validateRunContainer,
|
|
224
|
+
choices: runContainers,
|
|
221
225
|
} );
|
|
222
226
|
args.positional( 'command', {
|
|
223
227
|
type: 'array',
|
|
@@ -254,10 +258,16 @@ module.exports = function cli() {
|
|
|
254
258
|
withSpinner( env.destroy )
|
|
255
259
|
);
|
|
256
260
|
yargs.command(
|
|
257
|
-
'
|
|
258
|
-
'Get the
|
|
259
|
-
() => {
|
|
260
|
-
|
|
261
|
+
'status',
|
|
262
|
+
'Get the status of the wp-env environment including URLs, ports, and configuration.',
|
|
263
|
+
( args ) => {
|
|
264
|
+
args.option( 'json', {
|
|
265
|
+
type: 'boolean',
|
|
266
|
+
describe: 'Output status as JSON.',
|
|
267
|
+
default: false,
|
|
268
|
+
} );
|
|
269
|
+
},
|
|
270
|
+
withSpinner( env.status )
|
|
261
271
|
);
|
|
262
272
|
|
|
263
273
|
return yargs;
|
package/lib/commands/clean.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* External dependencies
|
|
4
4
|
*/
|
|
5
|
-
const
|
|
5
|
+
const path = require( 'path' );
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Internal dependencies
|
|
9
9
|
*/
|
|
10
|
-
const initConfig = require( '../init-config' );
|
|
11
|
-
const { configureWordPress, resetDatabase } = require( '../wordpress' );
|
|
12
10
|
const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
|
|
11
|
+
const { loadConfig } = require( '../config' );
|
|
12
|
+
const { getRuntime, detectRuntime } = require( '../runtime' );
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* @typedef {import('../wordpress').WPEnvironment} WPEnvironment
|
|
@@ -31,43 +31,12 @@ module.exports = async function clean( {
|
|
|
31
31
|
scripts,
|
|
32
32
|
debug,
|
|
33
33
|
} ) {
|
|
34
|
-
const config = await
|
|
34
|
+
const config = await loadConfig( path.resolve( '.' ) );
|
|
35
|
+
const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
environment === 'all' ? 's' : ''
|
|
38
|
-
}`;
|
|
39
|
-
spinner.text = `Cleaning ${ description }.`;
|
|
40
|
-
|
|
41
|
-
const tasks = [];
|
|
42
|
-
|
|
43
|
-
// Start the database first to avoid race conditions where all tasks create
|
|
44
|
-
// different docker networks with the same name.
|
|
45
|
-
await dockerCompose.upOne( 'mysql', {
|
|
46
|
-
config: config.dockerComposeConfigPath,
|
|
47
|
-
log: config.debug,
|
|
48
|
-
} );
|
|
49
|
-
|
|
50
|
-
if ( environment === 'all' || environment === 'development' ) {
|
|
51
|
-
tasks.push(
|
|
52
|
-
resetDatabase( 'development', config )
|
|
53
|
-
.then( () => configureWordPress( 'development', config ) )
|
|
54
|
-
.catch( () => {} )
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if ( environment === 'all' || environment === 'tests' ) {
|
|
59
|
-
tasks.push(
|
|
60
|
-
resetDatabase( 'tests', config )
|
|
61
|
-
.then( () => configureWordPress( 'tests', config ) )
|
|
62
|
-
.catch( () => {} )
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
await Promise.all( tasks );
|
|
37
|
+
await runtime.clean( config, { environment, spinner, debug } );
|
|
67
38
|
|
|
68
39
|
if ( scripts ) {
|
|
69
40
|
await executeLifecycleScript( 'afterClean', config, spinner );
|
|
70
41
|
}
|
|
71
|
-
|
|
72
|
-
spinner.text = `Cleaned ${ description }.`;
|
|
73
42
|
};
|
package/lib/commands/destroy.js
CHANGED
|
@@ -2,21 +2,16 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* External dependencies
|
|
4
4
|
*/
|
|
5
|
-
const { v2: dockerCompose } = require( 'docker-compose' );
|
|
6
5
|
const fs = require( 'fs' ).promises;
|
|
7
6
|
const path = require( 'path' );
|
|
8
7
|
const { confirm } = require( '@inquirer/prompts' );
|
|
9
8
|
|
|
10
|
-
/**
|
|
11
|
-
* Promisified dependencies
|
|
12
|
-
*/
|
|
13
|
-
const { rimraf } = require( 'rimraf' );
|
|
14
|
-
|
|
15
9
|
/**
|
|
16
10
|
* Internal dependencies
|
|
17
11
|
*/
|
|
18
12
|
const { loadConfig } = require( '../config' );
|
|
19
13
|
const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
|
|
14
|
+
const { getRuntime, detectRuntime } = require( '../runtime' );
|
|
20
15
|
|
|
21
16
|
/**
|
|
22
17
|
* Destroy the development server.
|
|
@@ -36,9 +31,9 @@ module.exports = async function destroy( { spinner, scripts, debug } ) {
|
|
|
36
31
|
return;
|
|
37
32
|
}
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
34
|
+
const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
|
|
35
|
+
|
|
36
|
+
spinner.info( runtime.getDestroyWarningMessage() );
|
|
42
37
|
|
|
43
38
|
let yesDelete = false;
|
|
44
39
|
try {
|
|
@@ -61,24 +56,9 @@ module.exports = async function destroy( { spinner, scripts, debug } ) {
|
|
|
61
56
|
return;
|
|
62
57
|
}
|
|
63
58
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
await dockerCompose.down( {
|
|
67
|
-
config: config.dockerComposeConfigPath,
|
|
68
|
-
commandOptions: [ '--volumes', '--remove-orphans', '--rmi', 'all' ],
|
|
69
|
-
log: debug,
|
|
70
|
-
} );
|
|
71
|
-
|
|
72
|
-
spinner.text = 'Removing local files.';
|
|
73
|
-
// Note: there is a race condition where docker compose actually hasn't finished
|
|
74
|
-
// by this point, which causes rimraf to fail. We need to wait at least 2.5-5s,
|
|
75
|
-
// but using 10s in case it's dependant on the machine.
|
|
76
|
-
await new Promise( ( resolve ) => setTimeout( resolve, 10000 ) );
|
|
77
|
-
await rimraf( config.workDirectoryPath );
|
|
59
|
+
await runtime.destroy( config, { spinner, debug } );
|
|
78
60
|
|
|
79
61
|
if ( scripts ) {
|
|
80
62
|
await executeLifecycleScript( 'afterDestroy', config, spinner );
|
|
81
63
|
}
|
|
82
|
-
|
|
83
|
-
spinner.text = 'Removed WordPress environment.';
|
|
84
64
|
};
|
package/lib/commands/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const clean = require( './clean' );
|
|
|
8
8
|
const run = require( './run' );
|
|
9
9
|
const destroy = require( './destroy' );
|
|
10
10
|
const logs = require( './logs' );
|
|
11
|
-
const
|
|
11
|
+
const status = require( './status' );
|
|
12
12
|
|
|
13
13
|
module.exports = {
|
|
14
14
|
start,
|
|
@@ -17,5 +17,5 @@ module.exports = {
|
|
|
17
17
|
run,
|
|
18
18
|
destroy,
|
|
19
19
|
logs,
|
|
20
|
-
|
|
20
|
+
status,
|
|
21
21
|
};
|
package/lib/commands/logs.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* External dependencies
|
|
4
4
|
*/
|
|
5
|
-
const
|
|
5
|
+
const path = require( 'path' );
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Internal dependencies
|
|
9
9
|
*/
|
|
10
|
-
const
|
|
10
|
+
const { loadConfig } = require( '../config' );
|
|
11
|
+
const { getRuntime, detectRuntime } = require( '../runtime' );
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Displays the Docker & PHP logs on the given environment.
|
|
@@ -19,59 +20,7 @@ const initConfig = require( '../init-config' );
|
|
|
19
20
|
* @param {boolean} options.debug True if debug mode is enabled.
|
|
20
21
|
*/
|
|
21
22
|
module.exports = async function logs( { environment, watch, spinner, debug } ) {
|
|
22
|
-
const config = await
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// few lines in the logs as they happen, which isn't a good look. So only
|
|
26
|
-
// show the message if we are not watching the logs.
|
|
27
|
-
if ( ! watch ) {
|
|
28
|
-
spinner.text = `Showing logs for the ${ environment } environment.`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const servicesToWatch =
|
|
32
|
-
environment === 'all'
|
|
33
|
-
? [ 'tests-wordpress', 'wordpress' ]
|
|
34
|
-
: [ environment === 'tests' ? 'tests-wordpress' : 'wordpress' ];
|
|
35
|
-
|
|
36
|
-
const output = await Promise.all( [
|
|
37
|
-
...servicesToWatch.map( ( service ) =>
|
|
38
|
-
dockerCompose.logs( service, {
|
|
39
|
-
config: config.dockerComposeConfigPath,
|
|
40
|
-
log: watch, // Must log inline if we are watching the log output.
|
|
41
|
-
commandOptions: watch ? [ '--follow' ] : [],
|
|
42
|
-
} )
|
|
43
|
-
),
|
|
44
|
-
] );
|
|
45
|
-
|
|
46
|
-
// Combine the results from each docker output.
|
|
47
|
-
const result = output.reduce(
|
|
48
|
-
( acc, current ) => {
|
|
49
|
-
if ( current.out ) {
|
|
50
|
-
acc.out = acc.out.concat( current.out );
|
|
51
|
-
}
|
|
52
|
-
if ( current.err ) {
|
|
53
|
-
acc.err = acc.err.concat( current.err );
|
|
54
|
-
}
|
|
55
|
-
if ( current.exitCode !== 0 ) {
|
|
56
|
-
acc.hasNon0ExitCode = true;
|
|
57
|
-
}
|
|
58
|
-
return acc;
|
|
59
|
-
},
|
|
60
|
-
{ out: '', err: '', hasNon0ExitCode: false }
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if ( result.out.length ) {
|
|
64
|
-
console.log(
|
|
65
|
-
process.stdout.isTTY ? `\n\n${ result.out }\n\n` : result.out
|
|
66
|
-
);
|
|
67
|
-
} else if ( result.err.length ) {
|
|
68
|
-
console.error(
|
|
69
|
-
process.stdout.isTTY ? `\n\n${ result.err }\n\n` : result.err
|
|
70
|
-
);
|
|
71
|
-
if ( result.hasNon0ExitCode ) {
|
|
72
|
-
throw result.err;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
spinner.text = 'Finished showing logs.';
|
|
23
|
+
const config = await loadConfig( path.resolve( '.' ) );
|
|
24
|
+
const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
|
|
25
|
+
await runtime.logs( config, { environment, watch, spinner, debug } );
|
|
77
26
|
};
|
package/lib/commands/run.js
CHANGED
|
@@ -2,18 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* External dependencies
|
|
4
4
|
*/
|
|
5
|
-
const { spawn } = require( 'child_process' );
|
|
6
5
|
const path = require( 'path' );
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Internal dependencies
|
|
10
9
|
*/
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @typedef {import('../config').WPConfig} WPConfig
|
|
16
|
-
*/
|
|
10
|
+
const { loadConfig } = require( '../config' );
|
|
11
|
+
const { getRuntime, detectRuntime } = require( '../runtime' );
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Runs an arbitrary command on the given Docker container.
|
|
@@ -34,7 +29,8 @@ module.exports = async function run( {
|
|
|
34
29
|
spinner,
|
|
35
30
|
debug,
|
|
36
31
|
} ) {
|
|
37
|
-
const config = await
|
|
32
|
+
const config = await loadConfig( path.resolve( '.' ) );
|
|
33
|
+
const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
|
|
38
34
|
|
|
39
35
|
// Include any double dashed arguments in the command so that we can pass them to Docker.
|
|
40
36
|
// This lets users pass options that the command defines without them being parsed.
|
|
@@ -42,106 +38,5 @@ module.exports = async function run( {
|
|
|
42
38
|
command.push( ...doubleDashedArgs );
|
|
43
39
|
}
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
const joinedCommand = command.join( ' ' );
|
|
47
|
-
showCommandTips( joinedCommand, container, spinner );
|
|
48
|
-
|
|
49
|
-
await spawnCommandDirectly( config, container, command, envCwd, spinner );
|
|
50
|
-
|
|
51
|
-
spinner.text = `Ran \`${ joinedCommand }\` in '${ container }'.`;
|
|
41
|
+
await runtime.run( config, { container, command, envCwd, spinner, debug } );
|
|
52
42
|
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Runs an arbitrary command on the given Docker container.
|
|
56
|
-
*
|
|
57
|
-
* @param {WPConfig} config The wp-env configuration.
|
|
58
|
-
* @param {string} container The Docker container to run the command on.
|
|
59
|
-
* @param {string[]} command The command to run.
|
|
60
|
-
* @param {string} envCwd The working directory for the command to be executed from.
|
|
61
|
-
* @param {Object} spinner A CLI spinner which indicates progress.
|
|
62
|
-
*/
|
|
63
|
-
function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
|
|
64
|
-
// Both the `wordpress` and `tests-wordpress` containers have the host's
|
|
65
|
-
// user so that they can maintain ownership parity with the host OS.
|
|
66
|
-
// We should run any commands as that user so that they are able
|
|
67
|
-
// to interact with the files mounted from the host.
|
|
68
|
-
const hostUser = getHostUser();
|
|
69
|
-
|
|
70
|
-
// Since Docker requires absolute paths, we should resolve the input to a POSIX path.
|
|
71
|
-
// This is needed because Windows resolves relative paths from the C: drive.
|
|
72
|
-
envCwd = path.posix.resolve(
|
|
73
|
-
// Not all containers have the same starting working directory.
|
|
74
|
-
container === 'mysql' || container === 'tests-mysql'
|
|
75
|
-
? '/'
|
|
76
|
-
: '/var/www/html',
|
|
77
|
-
// Remove spaces and single quotes from both ends of the path.
|
|
78
|
-
// This is needed because Windows treats single quotes as a literal character.
|
|
79
|
-
envCwd.trim().replace( /^'|'$/g, '' )
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const composeCommand = [
|
|
83
|
-
'compose',
|
|
84
|
-
'-f',
|
|
85
|
-
config.dockerComposeConfigPath,
|
|
86
|
-
'exec',
|
|
87
|
-
'-w',
|
|
88
|
-
envCwd,
|
|
89
|
-
'--user',
|
|
90
|
-
hostUser.fullUser,
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
if ( ! process.stdout.isTTY ) {
|
|
94
|
-
composeCommand.push( '-T' );
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
composeCommand.push( container, ...command );
|
|
98
|
-
|
|
99
|
-
return new Promise( ( resolve, reject ) => {
|
|
100
|
-
// Note: since the npm docker-compose package uses the -T option, we
|
|
101
|
-
// cannot use it to spawn an interactive command. Thus, we run docker-
|
|
102
|
-
// compose on the CLI directly.
|
|
103
|
-
const childProc = spawn(
|
|
104
|
-
'docker',
|
|
105
|
-
composeCommand,
|
|
106
|
-
{ stdio: 'inherit' },
|
|
107
|
-
spinner
|
|
108
|
-
);
|
|
109
|
-
childProc.on( 'error', reject );
|
|
110
|
-
childProc.on( 'exit', ( code ) => {
|
|
111
|
-
// Code 130 is set if the user tries to exit with ctrl-c before using
|
|
112
|
-
// ctrl-d (so it is not an error which should fail the script.)
|
|
113
|
-
if ( code === 0 || code === 130 ) {
|
|
114
|
-
resolve();
|
|
115
|
-
} else {
|
|
116
|
-
reject( `Command failed with exit code ${ code }` );
|
|
117
|
-
}
|
|
118
|
-
} );
|
|
119
|
-
} );
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* This shows a contextual tip for the command being run. Certain commands (like
|
|
124
|
-
* bash) may have weird behavior (exit with ctrl-d instead of ctrl-c or ctrl-z),
|
|
125
|
-
* so we want the user to have that information without having to ask someone.
|
|
126
|
-
*
|
|
127
|
-
* @param {string} joinedCommand The command for which to show a tip joined by spaces.
|
|
128
|
-
* @param {string} container The container the command will be run on.
|
|
129
|
-
* @param {Object} spinner A spinner object to show progress.
|
|
130
|
-
*/
|
|
131
|
-
function showCommandTips( joinedCommand, container, spinner ) {
|
|
132
|
-
if ( ! joinedCommand.length ) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const tip = `Starting '${ joinedCommand }' on the ${ container } container. ${ ( () => {
|
|
137
|
-
switch ( joinedCommand ) {
|
|
138
|
-
case 'bash':
|
|
139
|
-
return 'Exit bash with ctrl-d.';
|
|
140
|
-
case 'wp shell':
|
|
141
|
-
return 'Exit the WordPress shell with ctrl-c.';
|
|
142
|
-
default:
|
|
143
|
-
return '';
|
|
144
|
-
}
|
|
145
|
-
} )() }\n`;
|
|
146
|
-
spinner.info( tip );
|
|
147
|
-
}
|