/** * Caches the download, and uses cached if available. * * @access public * * @param string $package The URI of the package. If this is the full path to an * existing local file, it will be returned untouched. * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object. */ public function download_package($package) { /** * Filter whether to return the package. * * @since 3.7.0 * * @param bool $reply Whether to bail without returning the package. Default is false. * @param string $package The package file name. * @param object $this The WP_Upgrader instance. */ $reply = apply_filters('upgrader_pre_download', false, $package, $this); if (false !== $reply) { return $reply; } // Check if package is a local or remote file. Bail if it's local. if (!preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package)) { return $package; } if (empty($package)) { return new \WP_Error('no_package', $this->strings['no_package']); } $language_update = $this->skin->language_update; $type = $language_update->type; $slug = empty($language_update->slug) ? 'default' : $language_update->slug; $updated = strtotime($language_update->updated); $version = $language_update->version; $language = $language_update->language; $ext = pathinfo($package, PATHINFO_EXTENSION); $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.' . $ext; $cache = WP_CLI::get_cache(); $cache_key = "translation/{$type}-{$slug}-{$version}-{$language}-{$updated}.{$ext}"; $cache_file = $cache->has($cache_key); if ($cache_file) { WP_CLI::log("Using cached file '{$cache_file}'..."); copy($cache_file, $temp); return $temp; } else { /* * Download to a temporary file because piping from cURL to tar is flaky * on MinGW (and probably in other environments too). */ $headers = array('Accept' => 'application/json'); $options = array('timeout' => 600, 'filename' => $temp); $this->skin->feedback('downloading_package', $package); /** @var \Requests_Response|null $req */ $req = Utils\http_request('GET', $package, null, $headers, $options); if (!is_null($req) && $req->status_code !== 200) { return new \WP_Error('download_failed', $this->strings['download_failed']); } $cache->import($cache_key, $temp); return $temp; } }
function download_package($package) { /** * Filter whether to return the package. * * @since 3.7.0 * * @param bool $reply Whether to bail without returning the package. Default is false. * @param string $package The package file name. * @param object $this The WP_Upgrader instance. */ $reply = apply_filters('upgrader_pre_download', false, $package, $this); if (false !== $reply) { return $reply; } if (!preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package)) { //Local file or remote? return $package; } //must be a local file.. if (empty($package)) { return new WP_Error('no_package', $this->strings['no_package']); } $filename = pathinfo($package, PATHINFO_FILENAME); $ext = pathinfo($package, PATHINFO_EXTENSION); $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.' . $ext; $cache = WP_CLI::get_cache(); $update = $GLOBALS['wp_cli_update_obj']; $cache_key = "core/{$filename}-{$update->locale}.{$ext}"; $cache_file = $cache->has($cache_key); if ($cache_file) { WP_CLI::log("Using cached file '{$cache_file}'..."); copy($cache_file, $temp); return $temp; } else { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; $headers = array('Accept' => 'application/json'); $options = array('timeout' => 600, 'filename' => $temp); $this->skin->feedback('downloading_package', $package); /** @var \Requests_Response|null $req */ $req = Utils\http_request('GET', $package, null, $headers, $options); if (!is_null($req) && $req->status_code !== 200) { return new \WP_Error('download_failed', $this->strings['download_failed']); } $cache->import($cache_key, $temp); return $temp; } }
/** * 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"); } }