File: /wordpress/mu-plugins/atomic-cli-managed-software.php
<?php
if ( ! class_exists( 'Atomic_Platform_Managed_Software_Commands' ) ) {
class Atomic_Platform_Managed_Software_Commands {
/**
* Symlinks a managed plugin into the site's plugins directory.
*
* ## OPTIONS
*
* <plugin>
* : The name of the managed plugin to use.
*
* [--remove-existing]
* : If there is an existing directory or symlink in the way, remove it without asking.
*
* [--activate]
* : Indicates that the managed plugin should be activated
*/
public static function use_managed_plugin( $args, $assoc_args = array() ) {
$plugin_to_symlink = $args[0];
if ( 'wpcomsh' === $plugin_to_symlink ) {
// wpcomsh is in the managed plugins directory, but it should not be symlinked into the plugins directory.
WP_CLI::error( 'Cannot symlink wpcomsh' );
}
if ( false === chdir( WP_PLUGIN_DIR ) ) {
WP_CLI::error( "Cannot switch to plugins directory '" . WP_PLUGIN_DIR . "'" );
}
$managed_plugin_relative_path = _atomic_platform_managed_symlink( 'plugin', $plugin_to_symlink, 'latest' );
if ( false === realpath( $managed_plugin_relative_path ) ) {
WP_CLI::error( "'$plugin_to_symlink' is not a managed plugin" );
}
$already_symlinked = false;
if ( realpath( $plugin_to_symlink ) === realpath( $managed_plugin_relative_path ) ) {
$already_symlinked = true;
} elseif ( is_dir( $plugin_to_symlink ) ) {
$permission_to_remove = false;
if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'remove-existing', false ) ) {
$permission_to_remove = true;
} elseif ( static::cli_confirm( "Plugin '$plugin_to_symlink' exists. Delete it and replace with symlink to managed plugin?" ) ) {
$permission_to_remove = true;
}
if ( ! $permission_to_remove ) {
exit( -1 );
}
if ( is_link( $plugin_to_symlink ) ) {
if ( false === unlink( $plugin_to_symlink ) ) {
WP_CLI::error( "Failed to remove conflicting symlink '$plugin_to_symlink'" );
exit( -1 );
}
} else {
WP_CLI::runcommand(
"--skip-plugins --skip-themes plugin delete '$plugin_to_symlink'",
array(
'launch' => false,
'exit_error' => true,
)
);
}
}
if ( $already_symlinked ) {
WP_CLI::success( "Plugin '$plugin_to_symlink' is already symlinked" );
} elseif ( symlink( $managed_plugin_relative_path, $plugin_to_symlink ) ) {
// Delete the plugins cache so the symlinked plugin can be recognized
wp_cache_delete( 'plugins', 'plugins' );
WP_CLI::success( "Added symlink to managed plugin: $plugin_to_symlink" );
} else {
WP_CLI::error( "Failed to symlink managed plugin: $plugin_to_symlink" );
exit( -1 );
}
$activate = WP_CLI\Utils\get_flag_value( $assoc_args, 'activate', false );
if ( $activate ) {
WP_CLI::runcommand(
"--skip-plugins --skip-themes plugin activate '$plugin_to_symlink'",
array(
'launch' => false,
'exit_error' => true,
)
);
}
exit( 0 );
}
/**
* Installs an unmanaged plugin into the site's plugins directory. replacing a managed version if one exists.
*
* ## OPTIONS
*
* <plugin>
* : The name of the plugin.
*
* [--remove-existing]
* : If there is an existing directory or symlink in the way, remove it without asking.
*
* [--activate]
* : Indicates that the plugin should be activated.
*
* [--version]
* : The version to install.
*/
public static function use_unmanaged_plugin( $args, $assoc_args = array() ) {
$plugin_to_install = $args[0];
if ( false === chdir( WP_PLUGIN_DIR ) ) {
WP_CLI::error( "Cannot switch to plugins directory '" . WP_PLUGIN_DIR . "'" );
}
$install_path = WP_PLUGIN_DIR . "/$plugin_to_install";
$already_exists = is_link( $install_path ) || file_exists( $install_path );
$previous_version_path = false;
if ( $already_exists ) {
$permission_to_remove = false;
if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'remove-existing', false ) ) {
$permission_to_remove = true;
} elseif ( static::cli_confirm( "Plugin '$plugin_to_install' exists. Delete it and replace with an unmanaged plugin?" ) ) {
$permission_to_remove = true;
}
if ( ! $permission_to_remove ) {
exit( -1 );
}
WP_CLI::log( "Setting previous version aside until new install succeeds" );
$uuid = wp_generate_uuid4();
$previous_version_path = WP_PLUGIN_DIR . "/.previous-version-$plugin_to_install-$uuid";
if ( ! rename( $install_path, $previous_version_path ) ) {
WP_CLI::error( "Failed to move previous version to $previous_version_path" );
}
}
$command = "--skip-plugins --skip-themes plugin install $plugin_to_install --force";
$version = WP_CLI\Utils\get_flag_value( $assoc_args, 'version', false );
if ( false !== $version ) {
$command = "$command --version=$version";
}
$result = WP_CLI::runcommand(
$command,
array(
'return' => 'all',
'launch' => true,
'exit_error' => false,
)
);
if ( 0 !== $result->return_code ) {
WP_CLI::error( 'There was an error installing the plugin', false );
WP_CLI::log( $result->stderr );
if ( $previous_version_path ) {
WP_CLI::log( 'Restoring previous version...' );
if ( ! rename( $previous_version_path, $install_path ) ) {
WP_CLI::error(
"Failed to restore previous version from $previous_version_path to $install_path",
false
);
}
WP_CLI::log( 'Done' );
}
exit( -1 );
}
WP_CLI::success( "Installed unmanaged plugin: $plugin_to_install" );
$activate = WP_CLI\Utils\get_flag_value( $assoc_args, 'activate', false );
if ( $activate ) {
WP_CLI::runcommand(
"--skip-plugins --skip-themes plugin activate '$plugin_to_install'",
array(
'launch' => false,
'exit_error' => true,
)
);
}
if ( $previous_version_path ) {
WP_CLI::log( 'Cleaning up previous version...' );
$removal_shell_command = 'rm -r ' . escapeshellarg( $previous_version_path );
$removal_result_code = 0;
passthru( $removal_shell_command, $removal_result_code );
if ( 0 !== $removal_result_code ) {
WP_CLI::error( "Unable to clean up previous version: $previous_version_path" );
}
WP_CLI::log( 'Done' );
}
exit( 0 );
}
/**
* Symlinks a managed theme into the site's themes directory.
*
* ## OPTIONS
*
* <theme>
* : The managed theme to symlink.
*
* [--remove-existing]
* : If there is an existing directory or different symlink in the way, remove it without asking.
*
* [--activate]
* : Indicates that the symlinked theme should be activated
*/
public static function use_managed_theme( $args, $assoc_args = array() ) {
$theme_to_symlink = $args[0];
$themes_dir = get_theme_root();
if ( false === chdir( $themes_dir ) ) {
WP_CLI::error( "Cannot switch to themes directory '$themes_dir'" );
}
$candidate_managed_theme_paths = array_unique(
array(
// NOTE: pub and premium themes don't have nested `latest`and version directories.
_atomic_platform_managed_symlink( 'theme', $theme_to_symlink, 'pub' ),
_atomic_platform_managed_symlink( 'theme', $theme_to_symlink, 'premium' ),
// Consider root themes dir last because we want to favor WPCOM-managed things on WPCOM
// See https://wp.me/p9o2xV-1LC#comment-5417
_atomic_platform_managed_symlink( 'theme', $theme_to_symlink, 'latest' ),
)
);
$managed_theme_path = false;
foreach ( $candidate_managed_theme_paths as $candidate_path ) {
if ( false !== realpath( $candidate_path ) ) {
$managed_theme_path = $candidate_path;
break;
}
}
if ( false === $managed_theme_path ) {
WP_CLI::error( "'$theme_to_symlink' is not a managed theme" );
}
$already_symlinked = false;
if ( realpath( $theme_to_symlink ) === realpath( $managed_theme_path ) ) {
$already_symlinked = true;
} elseif ( is_dir( $theme_to_symlink ) ) {
$permission_to_remove = false;
if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'remove-existing', false ) ) {
$permission_to_remove = true;
} elseif ( static::cli_confirm( "Theme '$theme_to_symlink' exists. Delete it and replace with symlink to managed theme?" ) ) {
$permission_to_remove = true;
}
if ( ! $permission_to_remove ) {
exit( -1 );
}
if ( is_link( $theme_to_symlink ) ) {
if ( false === unlink( $theme_to_symlink ) ) {
WP_CLI::error( "Failed to remove conflicting symlink '$theme_to_symlink'" );
exit( -1 );
}
} else {
WP_CLI::runcommand(
"--skip-plugins --skip-themes theme delete '$theme_to_symlink' --force",
array(
'launch' => false,
'exit_error' => true,
)
);
}
}
if ( $already_symlinked ) {
WP_CLI::success( "Managed theme '$theme_to_symlink' is already symlinked" );
} elseif ( symlink( $managed_theme_path, $theme_to_symlink ) ) {
WP_CLI::success( "Added symlink to managed theme: $theme_to_symlink" );
} else {
WP_CLI::error( "Failed to symlink managed plugin: $theme_to_symlink" );
exit( -1 );
}
$activate = WP_CLI\Utils\get_flag_value( $assoc_args, 'activate', false );
if ( $activate ) {
WP_CLI::runcommand(
"--skip-plugins --skip-themes theme activate '$theme_to_symlink'",
array(
'launch' => true,
'exit_error' => true,
)
);
}
exit( 0 );
}
/**
* Installs an unmanaged theme into the site's themes directory, potentially replacing an existing version.
*
* ## OPTIONS
*
* <theme>
* : The name of the theme.
*
* [--remove-existing]
* : If there is an existing directory or symlink in the way, remove it without asking.
*
* [--activate]
* : Indicates that the theme should be activated.
*
* [--version]
* : The version to install.
*/
public static function use_unmanaged_theme( $args, $assoc_args = array() ) {
$theme_to_install = $args[0];
if ( get_stylesheet() === $theme_to_install ) {
WP_CLI::error( "Theme '$theme_to_install' cannot be converted while it is active" );
}
$themes_dir = get_theme_root();
if ( false === chdir( $themes_dir ) ) {
WP_CLI::error( "Cannot switch to themes directory '$themes_dir'" );
}
$install_path = "$themes_dir/$theme_to_install";
$already_exists = is_link( $install_path ) || file_exists( $install_path );
$previous_version_path = false;
if ( $already_exists ) {
$permission_to_remove = false;
if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'remove-existing', false ) ) {
$permission_to_remove = true;
} elseif ( static::cli_confirm( "Plugin '$theme_to_install' exists. Delete it and replace with an unmanaged theme?" ) ) {
$permission_to_remove = true;
}
if ( ! $permission_to_remove ) {
exit( -1 );
}
WP_CLI::log( "Setting previous version aside until new install succeeds" );
$uuid = wp_generate_uuid4();
$previous_version_path = "$themes_dir/.previous-version-$theme_to_install-$uuid";
if ( ! rename( $install_path, $previous_version_path ) ) {
WP_CLI::error( "Failed to move previous version to $previous_version_path" );
}
}
$command = "--skip-plugins --skip-themes theme install $theme_to_install --force";
$version = WP_CLI\Utils\get_flag_value( $assoc_args, 'version', false );
if ( false !== $version ) {
$command = "$command --version=$version";
}
$result = WP_CLI::runcommand(
$command,
array(
'return' => 'all',
'launch' => true,
'exit_error' => false,
)
);
if ( 0 !== $result->return_code ) {
WP_CLI::error( 'There was an error installing the theme', false );
WP_CLI::log( $result->stderr );
if ( $previous_version_path ) {
WP_CLI::log( 'Restoring previous version...' );
if ( ! rename( $previous_version_path, $install_path ) ) {
WP_CLI::error(
"Failed to restore previous version from $previous_version_path to $install_path",
false
);
}
WP_CLI::log( 'Done' );
}
exit( -1 );
}
WP_CLI::success( "Installed unmanaged theme: $theme_to_install" );
$activate = WP_CLI\Utils\get_flag_value( $assoc_args, 'activate', false );
if ( $activate ) {
WP_CLI::runcommand(
"--skip-plugins --skip-themes theme activate '$theme_to_install'",
array(
'launch' => false,
'exit_error' => true,
)
);
}
if ( $previous_version_path ) {
WP_CLI::log( 'Cleaning up previous version...' );
$removal_shell_command = 'rm -r ' . escapeshellarg( $previous_version_path );
$removal_result_code = 0;
passthru( $removal_shell_command, $removal_result_code );
if ( 0 !== $removal_result_code ) {
WP_CLI::error( "Unable to clean up previous version: $previous_version_path" );
}
WP_CLI::log( 'Done' );
}
exit( 0 );
}
/**
* Ask the user to confirm a yes/no question.
*
* @param string $question The yes/no question to ask the user.
* @return boolean Whether the user confirmed or not.
*/
public static function cli_confirm( $question ) {
fwrite( STDOUT, $question . ' [Y/n] ' );
$answer = strtolower( trim( fgets( STDIN ) ) );
return 'y' === $answer || ! $answer;
}
}
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::add_command(
'atomic plugin use-managed',
array( 'Atomic_Platform_Managed_Software_Commands', 'use_managed_plugin' )
);
WP_CLI::add_command(
'atomic plugin use-unmanaged',
array( 'Atomic_Platform_Managed_Software_Commands', 'use_unmanaged_plugin' )
);
WP_CLI::add_command(
'atomic theme use-managed',
array( 'Atomic_Platform_Managed_Software_Commands', 'use_managed_theme' )
);
WP_CLI::add_command(
'atomic theme use-unmanaged',
array( 'Atomic_Platform_Managed_Software_Commands', 'use_unmanaged_theme' )
);
}
}