public function testAddRepositoryCanOverrideDeepRepos() { $manipulator = new JsonManipulator('{ "repositories": { "baz": { "type": "package", "package": {} } } }'); $this->assertTrue($manipulator->addRepository('baz', array('type' => 'composer'))); $this->assertEquals('{ "repositories": { "baz": { "type": "composer" } } } ', $manipulator->getContents()); }
/** * Install a WP-CLI package. * * Packages are required to be a valid Composer package, and can be * specified as: * * * Package name from WP-CLI's package index. * * Git URL accessible by the current shell user. * * Path to a directory on the local machine. * * Local or remote .zip file. * * When installing a local directory, WP-CLI simply registers a * reference to the directory. If you move or delete the directory, WP-CLI's * reference breaks. * * When installing a .zip file, WP-CLI extracts the package to * `~/.wp-cli/packages/local/<package-name>`. * * ## OPTIONS * * <name|git|path|zip> * : Name, git URL, directory path, or .zip file for the package to install. * Names can optionally include a version constraint * (e.g. wp-cli/server-command:@stable). * * ## EXAMPLES * * # Install the latest development version from the package index. * $ wp package install wp-cli/server-command * Installing package wp-cli/server-command (dev-master) * Updating /home/person/.wp-cli/packages/composer.json to require the package... * Using Composer to install the package... * --- * Loading composer repositories with package information * Updating dependencies * Resolving dependencies through SAT * Dependency resolution completed in 0.005 seconds * Analyzed 732 packages to resolve dependencies * Analyzed 1034 rules to resolve dependencies * - Installing package * Writing lock file * Generating autoload files * --- * Success: Package installed. * * # Install the latest stable version. * $ wp package install wp-cli/server-command:@stable * * # Install a package hosted at a git URL. * $ wp package install git@github.com:runcommand/hook.git * * # Install a package in a .zip file. * $ wp package install google-sitemap-generator-cli.zip */ public function install($args, $assoc_args) { list($package_name) = $args; $git_package = $dir_package = false; $version = 'dev-master'; if ('.git' === strtolower(substr($package_name, -4, 4))) { $git_package = $package_name; preg_match('#([^:\\/]+\\/[^\\/]+)\\.git#', $package_name, $matches); if (!empty($matches[1])) { $package_name = $matches[1]; } else { WP_CLI::error("Couldn't parse package name from expected path '<name>/<package>'."); } } else { if (false !== strpos($package_name, '://') && false !== stripos($package_name, '.zip') || pathinfo($package_name, PATHINFO_EXTENSION) === 'zip' && is_file($package_name)) { // Download the remote ZIP file to a temp directory if (false !== strpos($package_name, '://')) { $temp = Utils\get_temp_dir() . uniqid('package_') . ".zip"; $options = array('timeout' => 600, 'filename' => $temp); $response = Utils\http_request('GET', $package_name, null, array(), $options); if (20 != substr($response->status_code, 0, 2)) { WP_CLI::error("Couldn't download package."); } $package_name = $temp; } $dir_package = Utils\get_temp_dir() . uniqid('package_'); try { // Extract the package to get the package name Extractor::extract($package_name, $dir_package); list($package_name, $version) = self::get_package_name_and_version_from_dir_package($dir_package); // Move to a location based on the package name $local_dir = rtrim(WP_CLI::get_runner()->get_packages_dir_path(), '/') . '/local/'; $actual_dir_package = $local_dir . str_replace('/', '-', $package_name); Extractor::copy_overwrite_files($dir_package, $actual_dir_package); Extractor::rmdir($dir_package); // Behold, the extracted package $dir_package = $actual_dir_package; } catch (Exception $e) { WP_CLI::error($e->getMessage()); } } else { if (is_dir($package_name) && file_exists($package_name . '/composer.json')) { $dir_package = $package_name; if (!Utils\is_path_absolute($dir_package)) { $dir_package = getcwd() . DIRECTORY_SEPARATOR . $dir_package; } list($package_name, $version) = self::get_package_name_and_version_from_dir_package($dir_package); } else { if (false !== strpos($package_name, ':')) { list($package_name, $version) = explode(':', $package_name); } $package = $this->get_community_package_by_name($package_name); if (!$package) { WP_CLI::error("Invalid package."); } } } } WP_CLI::log(sprintf("Installing package %s (%s)", $package_name, $version)); $composer_json_obj = $this->get_composer_json(); // Add the 'require' to composer.json WP_CLI::log(sprintf("Updating %s to require the package...", $composer_json_obj->getPath())); $composer_backup = file_get_contents($composer_json_obj->getPath()); $json_manipulator = new JsonManipulator($composer_backup); $json_manipulator->addMainKey('name', 'wp-cli/wp-cli'); $json_manipulator->addMainKey('version', self::get_wp_cli_version_composer()); $json_manipulator->addLink('require', $package_name, $version); $json_manipulator->addConfigSetting('secure-http', true); if ($git_package) { WP_CLI::log(sprintf('Registering %s as a VCS repository...', $git_package)); $json_manipulator->addRepository($package_name, array('type' => 'vcs', 'url' => $git_package)); } else { if ($dir_package) { WP_CLI::log(sprintf('Registering %s as a path repository...', $dir_package)); $json_manipulator->addRepository($package_name, array('type' => 'path', 'url' => $dir_package)); } } $composer_backup_decoded = json_decode($composer_backup, true); // If the composer file does not contain the current package index repository, refresh the repository definition. if (empty($composer_backup_decoded['repositories']['wp-cli']['url']) || self::PACKAGE_INDEX_URL != $composer_backup_decoded['repositories']['wp-cli']['url']) { WP_CLI::log('Updating package index repository url...'); $json_manipulator->addRepository('wp-cli', array('type' => 'composer', 'url' => self::PACKAGE_INDEX_URL)); } file_put_contents($composer_json_obj->getPath(), $json_manipulator->getContents()); try { $composer = $this->get_composer(); } catch (Exception $e) { WP_CLI::error($e->getMessage()); } // Set up the EventSubscriber $event_subscriber = new \WP_CLI\PackageManagerEventSubscriber(); $composer->getEventDispatcher()->addSubscriber($event_subscriber); // Set up the installer $install = Installer::create(new ComposerIO(), $composer); $install->setUpdate(true); // Installer class will only override composer.lock with this flag $install->setPreferSource(true); // Use VCS when VCS for easier contributions. // Try running the installer, but revert composer.json if failed WP_CLI::log('Using Composer to install the package...'); WP_CLI::log('---'); $res = false; try { $res = $install->run(); } catch (Exception $e) { WP_CLI::warning($e->getMessage()); } WP_CLI::log('---'); if (0 === $res) { WP_CLI::success("Package installed."); } else { file_put_contents($composer_json_obj->getPath(), $composer_backup); WP_CLI::error("Package installation failed (Composer return code {$res}). Reverted composer.json"); } }