diff --git a/packages/env/CHANGELOG.md b/packages/env/CHANGELOG.md index 61f195cbb1a543..098ffa7f5f468b 100644 --- a/packages/env/CHANGELOG.md +++ b/packages/env/CHANGELOG.md @@ -2,6 +2,7 @@ ### New Feature +- You may now override the directory in which `wp-env` creates generated files with the `WP_ENV_HOME` environment variable. The default directory is `~/.wp-env/` (or `~/wp-env/` on Linux). - The `.wp-env.json` coniguration file now accepts `port` and `testsPort` options which can be used to set the ports on which the docker instance is mounted. ## 1.0.0 (2020-02-10) diff --git a/packages/env/README.md b/packages/env/README.md index c651f228ffd4a7..71abc3fa61e017 100644 --- a/packages/env/README.md +++ b/packages/env/README.md @@ -137,6 +137,8 @@ $ wp-env start ## Command reference +`wp-env` creates generated files in the `wp-env` home directory. By default, this is `~/.wp-env`. The exception is Linux, where files are placed at `~/wp-env` [for compatibility with Snap Packages](https://github.com/WordPress/gutenberg/issues/20180#issuecomment-587046325). The `wp-env` home directory contains a subdirectory for each project named `/$md5_of_project_path`. To change the `wp-env` home directory, set the `WP_ENV_HOME` environment variable. For example, running `WP_ENV_HOME="something" wp-env start` will download the project files to the directory `./something/$md5_of_project_path` (relative to the current directory). + ### `wp-env start [ref]` ```sh diff --git a/packages/env/lib/config.js b/packages/env/lib/config.js index 19475b00eb5ffc..320d38ab0730fe 100644 --- a/packages/env/lib/config.js +++ b/packages/env/lib/config.js @@ -151,8 +151,7 @@ module.exports = { } const workDirectoryPath = path.resolve( - os.homedir(), - '.wp-env', + getHomeDirectory(), md5( configPath ) ); @@ -286,6 +285,32 @@ function getNumberFromEnvVariable( varName ) { return maybeNumber; } +/** + * Gets the `wp-env` home directory in which generated files are created. + * + * By default, '~/.wp-env/'. On Linux, '~/wp-env/'. Can be overriden with the + * WP_ENV_HOME environment variable. + * + * @return {string} The absolute path to the `wp-env` home directory. + */ +function getHomeDirectory() { + // Allow user to override download location. + if ( process.env.WP_ENV_HOME ) { + return path.resolve( process.env.WP_ENV_HOME ); + } + + /** + * Installing docker with Snap Packages on Linux is common, but does not + * support hidden directories. Therefore we use a public directory on Linux. + * + * @see https://github.com/WordPress/gutenberg/issues/20180#issuecomment-587046325 + */ + return path.resolve( + os.homedir(), + os.platform() === 'linux' ? 'wp-env' : '.wp-env' + ); +} + /** * Hashes the given string using the MD5 algorithm. * diff --git a/packages/env/lib/env.js b/packages/env/lib/env.js index 91da074979c2c2..187f5712e5d9d2 100644 --- a/packages/env/lib/env.js +++ b/packages/env/lib/env.js @@ -33,6 +33,19 @@ module.exports = { * @param {Object} options.spinner A CLI spinner which indicates progress. */ async start( { spinner } ) { + /** + * If the Docker image is already running and the `wp-env` files have been + * deleted, the start command will not complete successfully. Stopping + * the container before continuing allows the docker entrypoint script, + * which restores the files, to run again when we start the containers. + * + * Additionally, this serves as a way to restart the container entirely + * should the need arise. + * + * @see https://github.com/WordPress/gutenberg/pull/20253#issuecomment-587228440 + */ + await module.exports.stop( { spinner } ); + const config = await initConfig(); spinner.text = 'Downloading WordPress.'; diff --git a/packages/env/test/config.js b/packages/env/test/config.js index cdcd0b123b668c..181a5a3baec23e 100644 --- a/packages/env/test/config.js +++ b/packages/env/test/config.js @@ -3,6 +3,7 @@ * External dependencies */ const { readFile } = require( 'fs' ).promises; +const os = require( 'os' ); /** * Internal dependencies @@ -327,6 +328,71 @@ describe( 'readConfig', () => { testsPort: 8889, } ); } ); + + it( 'should use the WP_ENV_HOME environment variable only if specified', async () => { + readFile.mockImplementation( () => + Promise.resolve( JSON.stringify( {} ) ) + ); + const oldEnvHome = process.env.WP_ENV_HOME; + + expect.assertions( 2 ); + + process.env.WP_ENV_HOME = 'here/is/a/path'; + const configWith = await readConfig( '.wp-env.json' ); + expect( + configWith.workDirectoryPath.includes( 'here/is/a/path' ) + ).toBe( true ); + + process.env.WP_ENV_HOME = undefined; + const configWithout = await readConfig( '.wp-env.json' ); + expect( + configWithout.workDirectoryPath.includes( 'here/is/a/path' ) + ).toBe( false ); + + process.env.WP_ENV_HOME = oldEnvHome; + } ); + + it( 'should use the WP_ENV_HOME environment variable on Linux', async () => { + readFile.mockImplementation( () => + Promise.resolve( JSON.stringify( {} ) ) + ); + const oldEnvHome = process.env.WP_ENV_HOME; + const oldOsPlatform = os.platform; + os.platform = () => 'linux'; + + expect.assertions( 2 ); + + process.env.WP_ENV_HOME = 'here/is/a/path'; + const configWith = await readConfig( '.wp-env.json' ); + expect( + configWith.workDirectoryPath.includes( 'here/is/a/path' ) + ).toBe( true ); + + process.env.WP_ENV_HOME = undefined; + const configWithout = await readConfig( '.wp-env.json' ); + expect( + configWithout.workDirectoryPath.includes( 'here/is/a/path' ) + ).toBe( false ); + + process.env.WP_ENV_HOME = oldEnvHome; + os.platform = oldOsPlatform; + } ); + + it( 'should use a non-private folder on Linux', async () => { + readFile.mockImplementation( () => + Promise.resolve( JSON.stringify( {} ) ) + ); + const oldOsPlatform = os.platform; + os.platform = () => 'linux'; + + expect.assertions( 2 ); + + const config = await readConfig( '.wp-env.json' ); + expect( config.workDirectoryPath.includes( '.wp-env' ) ).toBe( false ); + expect( config.workDirectoryPath.includes( 'wp-env' ) ).toBe( true ); + + os.platform = oldOsPlatform; + } ); } ); /**