diff --git a/packages/env/lib/cli.js b/packages/env/lib/cli.js index cfeb312db3fa3b..9243cb4fcaf86f 100644 --- a/packages/env/lib/cli.js +++ b/packages/env/lib/cli.js @@ -67,6 +67,11 @@ const withSpinner = ( command ) => ( ...args ) => { module.exports = function cli() { yargs.usage( wpPrimary( '$0 ' ) ); + yargs.option( 'debug', { + type: 'boolean', + describe: 'Enable debug output.', + default: false, + } ); yargs.command( 'start', diff --git a/packages/env/lib/config.js b/packages/env/lib/config.js index 320d38ab0730fe..59e31847f66bc0 100644 --- a/packages/env/lib/config.js +++ b/packages/env/lib/config.js @@ -28,15 +28,16 @@ const HOME_PATH_PREFIX = `~${ path.sep }`; * A wp-env config object. * * @typedef Config - * @property {string} name Name of the environment. - * @property {string} configDirectoryPath Path to the .wp-env.json file. - * @property {string} workDirectoryPath Path to the work directory located in ~/.wp-env. - * @property {string} dockerComposeConfigPath Path to the docker-compose.yml file. - * @property {Source|null} coreSource The WordPress installation to load in the environment. - * @property {Source[]} pluginSources Plugins to load in the environment. - * @property {Source[]} themeSources Themes to load in the environment. - * @property {number} port The port on which to start the development WordPress environment. - * @property {number} testsPort The port on which to start the testing WordPress environment. + * @property {string} name Name of the environment. + * @property {string} configDirectoryPath Path to the .wp-env.json file. + * @property {string} workDirectoryPath Path to the work directory located in ~/.wp-env. + * @property {string} dockerComposeConfigPath Path to the docker-compose.yml file. + * @property {Source|null} coreSource The WordPress installation to load in the environment. + * @property {Source[]} pluginSources Plugins to load in the environment. + * @property {Source[]} themeSources Themes to load in the environment. + * @property {number} port The port on which to start the development WordPress environment. + * @property {number} testsPort The port on which to start the testing WordPress environment. + * @property {boolean} debug True if debug mode is enabled. */ /** diff --git a/packages/env/lib/download-source.js b/packages/env/lib/download-source.js index 507db9db5aa697..f3c8d5c5cbfd3b 100644 --- a/packages/env/lib/download-source.js +++ b/packages/env/lib/download-source.js @@ -12,9 +12,11 @@ const NodeGit = require( 'nodegit' ); * Downloads the given source if necessary. The specific action taken depends * on the source type. * - * @param {Source} source The source to download. - * @param {Object} options + * @param {Source} source The source to download. + * @param {Object} options * @param {Function} options.onProgress A function called with download progress. Will be invoked with one argument: a number that ranges from 0 to 1 which indicates current download progress for this source. + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. */ module.exports = async function downloadSource( source, options ) { if ( source.type === 'git' ) { @@ -26,11 +28,20 @@ module.exports = async function downloadSource( source, options ) { * Clones the git repository at `source.url` into `source.path`. If the * repository already exists, it is updated instead. * - * @param {Source} source The source to download. - * @param {Object} options + * @param {Source} source The source to download. + * @param {Object} options * @param {Function} options.onProgress A function called with download progress. Will be invoked with one argument: a number that ranges from 0 to 1 which indicates current download progress for this source. + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. */ -async function downloadGitSource( source, { onProgress } ) { +async function downloadGitSource( source, { onProgress, spinner, debug } ) { + const log = debug + ? // eslint-disable-next-line no-console + ( message ) => { + spinner.info( `NodeGit: ${ message }` ); + spinner.start(); + } + : () => {}; onProgress( 0 ); const gitFetchOptions = { @@ -50,20 +61,22 @@ async function downloadGitSource( source, { onProgress } ) { }, }; - // Clone or get the repo. + log( 'Cloning or getting the repo.' ); const repository = await NodeGit.Clone( source.url, source.path, gitFetchOptions - ) - // Repo already exists, get it. - .catch( () => NodeGit.Repository.open( source.path ) ); + ).catch( () => { + log( 'Repo already exists, get it.' ); + return NodeGit.Repository.open( source.path ); + } ); - // Checkout the specified ref. + log( 'Fetching the specified ref.' ); const remote = await repository.getRemote( 'origin' ); await remote.fetch( source.ref, gitFetchOptions.fetchOpts ); await remote.disconnect(); try { + log( 'Checking out the specified ref.' ); await repository.checkoutRef( await repository .getReference( 'FETCH_HEAD' ) @@ -77,7 +90,7 @@ async function downloadGitSource( source, { onProgress } ) { } ); } catch ( error ) { - // Some commit refs need to be set as detached. + log( 'Ref needs to be set as detached.' ); await repository.setHeadDetached( source.ref ); } diff --git a/packages/env/lib/env.js b/packages/env/lib/env.js index 187f5712e5d9d2..6bcf0c44bda9ea 100644 --- a/packages/env/lib/env.js +++ b/packages/env/lib/env.js @@ -29,10 +29,11 @@ module.exports = { /** * Starts the development server. * - * @param {Object} options - * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {Object} options + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. */ - async start( { spinner } ) { + async start( { spinner, debug } ) { /** * If the Docker image is already running and the `wp-env` files have been * deleted, the start command will not complete successfully. Stopping @@ -46,7 +47,7 @@ module.exports = { */ await module.exports.stop( { spinner } ); - const config = await initConfig(); + const config = await initConfig( { spinner, debug } ); spinner.text = 'Downloading WordPress.'; @@ -69,12 +70,15 @@ module.exports = { // Preemptively start the database while we wait for sources to download. dockerCompose.upOne( 'mysql', { config: config.dockerComposeConfigPath, + log: config.debug, } ), ( async () => { if ( config.coreSource ) { await downloadSource( config.coreSource, { onProgress: getProgressSetter( 'core' ), + spinner, + debug: config.debug, } ); await copyCoreFiles( config.coreSource.path, @@ -86,12 +90,16 @@ module.exports = { ...config.pluginSources.map( ( source ) => downloadSource( source, { onProgress: getProgressSetter( source.basename ), + spinner, + debug: config.debug, } ) ), ...config.themeSources.map( ( source ) => downloadSource( source, { onProgress: getProgressSetter( source.basename ), + spinner, + debug: config.debug, } ) ), ] ); @@ -100,6 +108,7 @@ module.exports = { await dockerCompose.upMany( [ 'wordpress', 'tests-wordpress' ], { config: config.dockerComposeConfigPath, + log: config.debug, } ); try { @@ -129,15 +138,22 @@ module.exports = { /** * Stops the development server. * - * @param {Object} options - * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {Object} options + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. */ - async stop( { spinner } ) { - const { dockerComposeConfigPath } = await initConfig(); + async stop( { spinner, debug } ) { + const { dockerComposeConfigPath } = await initConfig( { + spinner, + debug, + } ); spinner.text = 'Stopping WordPress.'; - await dockerCompose.down( { config: dockerComposeConfigPath } ); + await dockerCompose.down( { + config: dockerComposeConfigPath, + log: debug, + } ); spinner.text = 'Stopped WordPress.'; }, @@ -145,12 +161,13 @@ module.exports = { /** * Wipes the development server's database, the tests server's database, or both. * - * @param {Object} options - * @param {string} options.environment The environment to clean. Either 'development', 'tests', or 'all'. - * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {Object} options + * @param {string} options.environment The environment to clean. Either 'development', 'tests', or 'all'. + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. */ - async clean( { environment, spinner } ) { - const config = await initConfig(); + async clean( { environment, spinner, debug } ) { + const config = await initConfig( { spinner, debug } ); const description = `${ environment } environment${ environment === 'all' ? 's' : '' @@ -183,13 +200,14 @@ module.exports = { /** * Runs an arbitrary command on the given Docker container. * - * @param {Object} options - * @param {Object} options.container The Docker container to run the command on. - * @param {Object} options.command The command to run. - * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {Object} options + * @param {Object} options.container The Docker container to run the command on. + * @param {Object} options.command The command to run. + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. */ - async run( { container, command, spinner } ) { - const config = await initConfig(); + async run( { container, command, spinner, debug } ) { + const config = await initConfig( { spinner, debug } ); command = command.join( ' ' ); @@ -198,6 +216,7 @@ module.exports = { const result = await dockerCompose.run( container, command, { config: config.dockerComposeConfigPath, commandOptions: [ '--rm' ], + log: config.debug, } ); if ( result.out ) { @@ -223,19 +242,40 @@ module.exports = { * Initializes the local environment so that Docker commands can be run. Reads * ./.wp-env.json, creates ~/.wp-env, and creates ~/.wp-env/docker-compose.yml. * + * @param {Object} options + * @param {Object} options.spinner A CLI spinner which indicates progress. + * @param {boolean} options.debug True if debug mode is enabled. + * * @return {Config} The-env config object. */ -async function initConfig() { +async function initConfig( { spinner, debug } ) { const configPath = path.resolve( '.wp-env.json' ); const config = await readConfig( configPath ); + config.debug = debug; await fs.mkdir( config.workDirectoryPath, { recursive: true } ); + const dockerComposeConfig = buildDockerComposeConfig( config ); await fs.writeFile( config.dockerComposeConfigPath, - yaml.dump( buildDockerComposeConfig( config ) ) + yaml.dump( dockerComposeConfig ) ); + if ( config.debug ) { + spinner.info( + `Config:\n${ JSON.stringify( + config, + null, + 4 + ) }\n\nDocker Compose Config:\n${ JSON.stringify( + dockerComposeConfig, + null, + 4 + ) }` + ); + spinner.start(); + } + return config; } @@ -294,10 +334,11 @@ async function retry( action, { times, delay = 5000 } ) { * * @param {Config} config The wp-env config object. */ -async function checkDatabaseConnection( { dockerComposeConfigPath } ) { +async function checkDatabaseConnection( { dockerComposeConfigPath, debug } ) { await dockerCompose.run( 'cli', 'wp db check', { config: dockerComposeConfigPath, commandOptions: [ '--rm' ], + log: debug, } ); } @@ -313,6 +354,7 @@ async function configureWordPress( environment, config ) { const options = { config: config.dockerComposeConfigPath, commandOptions: [ '--rm' ], + log: config.debug, }; const port = environment === 'development' ? config.port : config.testsPort; @@ -356,10 +398,14 @@ async function configureWordPress( environment, config ) { * @param {string} environment The environment to clean. Either 'development', 'tests', or 'all'. * @param {Config} config The wp-env config object. */ -async function resetDatabase( environment, { dockerComposeConfigPath } ) { +async function resetDatabase( + environment, + { dockerComposeConfigPath, debug } +) { const options = { config: dockerComposeConfigPath, commandOptions: [ '--rm' ], + log: debug, }; const tasks = [];