diff --git a/commands/core/core.drush.inc b/commands/core/core.drush.inc index 1db04ed544..a307d9d9a5 100644 --- a/commands/core/core.drush.inc +++ b/commands/core/core.drush.inc @@ -45,7 +45,6 @@ function core_drush_engine_type_info() { function core_drush_engine_drupal() { $engines = array( 'environment' => array(), - 'pm' => array(), ); return $engines; } diff --git a/commands/core/drupal/environment.inc b/commands/core/drupal/environment.inc index f220aa015b..452370fa34 100644 --- a/commands/core/drupal/environment.inc +++ b/commands/core/drupal/environment.inc @@ -8,109 +8,8 @@ */ use Drupal\Core\Site\Settings; -use Drupal\Core\StreamWrapper\PrivateStream; -use Drupal\Core\StreamWrapper\PublicStream; -use Drush\Log\LogLevel; use Drupal\Core\Logger\RfcLogLevel; -/** - * Get complete information for all available modules. - * - * @param $include_hidden - * Boolean to indicate whether hidden modules should be excluded or not. - * @return - * An array containing module info for all available modules. - */ -function drush_get_modules($include_hidden = TRUE) { - $modules = system_rebuild_module_data(); - - foreach ($modules as $key => $module) { - if ((!$include_hidden) && (!empty($module->info['hidden']))) { - unset($modules[$key]); - } - else { - $module->schema_version = drupal_get_installed_schema_version($key); - } - } - - return $modules; -} - -/** - * Returns drupal required modules, including modules declared as required dynamically. - */ -function _drush_drupal_required_modules($module_info) { - $required = drupal_required_modules(); - foreach ($module_info as $name => $module) { - if (isset($module->info['required']) && $module->info['required']) { - $required[] = $name; - } - } - return array_unique($required); -} - -/** - * Return dependencies and its status for modules. - * - * @param $modules - * Array of module names - * @param $module_info - * Drupal 'files' array for modules as returned by drush_get_modules(). - * @return - * Array with dependencies and status for $modules - */ -function drush_check_module_dependencies($modules, $module_info) { - $status = array(); - foreach ($modules as $key => $module) { - $dependencies = array_reverse($module_info[$module]->requires); - $unmet_dependencies = array_diff(array_keys($dependencies), array_keys($module_info)); - if (!empty($unmet_dependencies)) { - $status[$key]['error'] = array( - 'code' => 'DRUSH_PM_ENABLE_DEPENDENCY_NOT_FOUND', - 'message' => dt('Module !module cannot be enabled because it depends on the following modules which could not be found: !unmet_dependencies', array('!module' => $module, '!unmet_dependencies' => implode(',', $unmet_dependencies))) - ); - } - else { - // check for version incompatibility - foreach ($dependencies as $dependency_name => $v) { - $current_version = $module_info[$dependency_name]->info['version']; - $current_version = str_replace(drush_get_drupal_core_compatibility() . '-', '', $current_version); - $incompatibility = drupal_check_incompatibility($v, $current_version); - if (isset($incompatibility)) { - $status[$key]['error'] = array( - 'code' => 'DRUSH_PM_ENABLE_DEPENDENCY_VERSION_MISMATCH', - 'message' => dt('Module !module cannot be enabled because it depends on !dependency !required_version but !current_version is available', array('!module' => $module, '!dependency' => $dependency_name, '!required_version' => $incompatibility, '!current_version' => $current_version)) - ); - } - } - } - $status[$key]['unmet-dependencies'] = $unmet_dependencies; - $status[$key]['dependencies'] = $dependencies; - } - - return $status; -} - -/** - * Return dependents of modules. - * - * @param $modules - * Array of module names - * @param $module_info - * Drupal 'files' array for modules as returned by drush_get_modules(). - * @return - * Array with dependents for each one of $modules - */ -function drush_module_dependents($modules, $module_info) { - $dependents = array(); - foreach ($modules as $module) { - $keys = array_keys($module_info[$module]->required_by); - $dependents = array_merge($dependents, array_combine($keys, $keys)); - } - - return array_unique($dependents); -} - /** * Returns a list of enabled modules. * @@ -121,26 +20,6 @@ function drush_module_list() { return array_combine($modules, $modules); } -/** - * Installs a given list of modules. - * - * @see \Drupal\Core\Extension\ModuleInstallerInterface::install() - * - */ -function drush_module_install($module_list, $enable_dependencies = TRUE) { - return \Drupal::service('module_installer')->install($module_list, $enable_dependencies); -} - -/** - * Checks that a given module exists and is enabled. - * - * @see \Drupal\Core\Extension\ModuleHandlerInterface::moduleExists() - * - */ -function drush_module_exists($module) { - return \Drupal::moduleHandler()->moduleExists($module); -} - /** * Determines which modules are implementing a hook. * @@ -163,215 +42,3 @@ function drush_module_implements($hook, $sort = FALSE, $reset = FALSE) { } return \Drupal::moduleHandler()->getImplementations($hook); } - -/** - * Return a list of modules from a list of named modules. - * Both enabled and disabled/uninstalled modules are returned. - */ -function drush_get_named_extensions_list($extensions) { - $result = array(); - $modules = drush_get_modules(); - foreach($modules as $name => $module) { - if (in_array($name, $extensions)) { - $result[$name] = $module; - } - } - $themes = drush_get_themes(); - foreach($themes as $name => $theme) { - if (in_array($name, $extensions)) { - $result[$name] = $theme; - } - } - return $result; -} - -/** - * Enable a list of modules. It is assumed the list contains all the dependencies not already enabled. - * - * @param $modules - * Array of module names - */ -function drush_module_enable($modules) { - // The list of modules already have all the dependencies, but they might not - // be in the correct order. Still pass $enable_dependencies = TRUE so that - // Drupal will enable the modules in the correct order. - drush_module_install($modules); - - // Our logger got blown away during the container rebuild above. - $boot = \Drush::bootstrapManager()->bootstrap(); - $boot->add_logger(); - - // Flush all caches. No longer needed in D8 per https://github.com/drush-ops/drush/issues/1207 - // drupal_flush_all_caches(); -} - -/** - * Disable a list of modules. It is assumed the list contains all dependents not already disabled. - * - * @param $modules - * Array of module names - */ -function drush_module_disable($modules) { - drush_set_error('DRUSH_MODULE_DISABLE', dt('Drupal 8 does not support disabling modules. Use pm-uninstall instead.')); -} - -/** - * Uninstall a list of modules. - * - * @param $modules - * Array of module names - * - * @see \Drupal\Core\Extension\ModuleInstallerInterface::uninstall() - */ -function drush_module_uninstall($modules) { - \Drupal::service('module_installer')->uninstall($modules); - // Our logger got blown away during the container rebuild above. - $boot = \Drush::bootstrapManager()->bootstrap(); - $boot->add_logger(); -} - -/** - * Invokes a hook in a particular module. - * - */ -function drush_module_invoke($module, $hook) { - $args = func_get_args(); - // Remove $module and $hook from the arguments. - unset($args[0], $args[1]); - return \Drupal::moduleHandler()->invoke($module, $hook, $args); -} - -/** - * Invokes a hook in all enabled modules that implement it. - * - */ -function drush_module_invoke_all($hook) { - $args = func_get_args(); - // Remove $hook from the arguments. - array_shift($args); - return \Drupal::moduleHandler()->invokeAll($hook, $args); -} - -/** - * Returns a list of enabled themes. Use drush_get_themes() if you need to rebuild - * and include hidden as well. - * - * @return \Drupal\Core\Extension\Extension[] - * A list of themes keyed by name. - */ -function drush_theme_list() { - $theme_handler = \Drupal::service('theme_handler'); - return $theme_handler->listInfo(); -} - -/** - * Get complete information for all available themes. - * - * @param $include_hidden - * Boolean to indicate whether hidden themes should be excluded or not. - * @return - * An array containing theme info for all available themes. - */ -function drush_get_themes($include_hidden = TRUE) { - $themes = \Drupal::service('theme_handler')->rebuildThemeData(); - foreach ($themes as $key => $theme) { - if (!$include_hidden) { - if (isset($theme->info['hidden'])) { - // Don't exclude default or admin theme. - if ($key != _drush_theme_default() && $key != _drush_theme_admin()) { - unset($themes[$key]); - } - } - } - } - - return $themes; -} - -/** - * Enable a list of themes. - * - * @param $themes - * Array of theme names. - */ -function drush_theme_enable($themes) { - \Drupal::service('theme_handler')->install($themes); -} - -/** - * Disable a list of themes. - * - * @param $themes - * Array of theme names. - */ -function drush_theme_disable($themes) { - drush_set_error('DRUSH_THEME_DISABLE', dt('Drupal 8 does not support disabling themes. Use pm-uninstall instead.')); -} - -/** - * Uninstall a list of themes. - * - * @param $themes - * Array of theme names - * - * @see \Drupal\Core\Extension\ThemeHandlerInterface::uninstall() - */ -function drush_theme_uninstall($themes) { - \Drupal::service('theme_handler')->uninstall($themes); - // Our logger got blown away during the container rebuild above. - $boot = \Drush::bootstrapManager()->bootstrap(); - $boot->add_logger(); -} - -function _drush_theme_default() { - return \Drupal::config('system.theme')->get('default'); -} - -function _drush_theme_admin() { - $theme = \Drupal::config('system.theme')->get('admin'); - return empty($theme) ? 'seven' : $theme; -} - -function _drush_file_public_path() { - return PublicStream::basePath(); -} - -function _drush_file_private_path() { - return PrivateStream::basePath(); -} - -/** - * Gets the extension name. - * - * @param $info - * The extension info. - * @return string - * The extension name. - */ -function _drush_extension_get_name($info) { - return $info->getName(); -} - -/** - * Gets the extension type. - * - * @param $info - * The extension info. - * @return string - * The extension type. - */ -function _drush_extension_get_type($info) { - return $info->getType(); -} - -/** - * Gets the extension path. - * - * @param $info - * The extension info. - * @return string - * The extension path. - */ -function _drush_extension_get_path($info) { - return $info->getPath(); -} diff --git a/commands/core/drupal/pm.inc b/commands/core/drupal/pm.inc deleted file mode 100644 index 0a64d2d6f5..0000000000 --- a/commands/core/drupal/pm.inc +++ /dev/null @@ -1,162 +0,0 @@ - $name)), LogLevel::WARNING); - } - - // Discard already disabled extensions. - foreach ($extensions as $name) { - if (!$extension_info[$name]->status) { - if ($extension_info[$name]->type == 'module') { - unset($modules[$name]); - } - else { - unset($themes[$name]); - } - drush_log(dt('!extension is already disabled.', array('!extension' => $name)), LogLevel::OK); - } - } - - // Discard default theme. - if (!empty($themes)) { - $default_theme = drush_theme_get_default(); - if (in_array($default_theme, $themes)) { - unset($themes[$default_theme]); - drush_log(dt('!theme is the default theme and can\'t be disabled.', array('!theme' => $default_theme)), LogLevel::OK); - } - } - - if (!empty($modules)) { - // Add enabled dependents to the list of modules to disable. - $dependents = drush_module_dependents($modules, $extension_info); - $dependents = array_intersect($dependents, drush_module_list()); - $modules = array_merge($modules, $dependents); - - // Discard required modules. - $required = drush_drupal_required_modules($extension_info); - foreach ($required as $module) { - if (isset($modules[$module])) { - unset($modules[$module]); - $info = $extension_info[$module]->info; - // No message for hidden modules. - if (!isset($info['hidden'])) { - $explanation = !empty($info['explanation']) ? ' ' . dt('Reason: !explanation.', array('!explanation' => strip_tags($info['explanation']))) : ''; - drush_log(dt('!module is a required module and can\'t be disabled.', array('!module' => $module)) . $explanation, LogLevel::OK); - } - } - } - } - - // Inform the user which extensions will finally be disabled. - $extensions = array_merge($modules, $themes); - if (empty($extensions)) { - return drush_log(dt('There were no extensions that could be disabled.'), LogLevel::OK); - } - else { - drush_print(dt('The following extensions will be disabled: !extensions', array('!extensions' => implode(', ', $extensions)))); - if(!drush_confirm(dt('Do you really want to continue?'))) { - return drush_user_abort(); - } - } - - // Disable themes. - if (!empty($themes)) { - drush_theme_disable($themes); - } - - // Disable modules and pass dependency validation in form submit. - if (!empty($modules)) { - drush_module_disable($modules); - } - - // Inform the user of final status. - $result_extensions = drush_get_named_extensions_list($extensions); - $problem_extensions = array(); - foreach ($result_extensions as $extension) { - if (!$extension->status) { - drush_log(dt('!extension was disabled successfully.', array('!extension' => $extension->name)), LogLevel::OK); - } - else { - $problem_extensions[] = $extension->name; - } - } - if (!empty($problem_extensions)) { - return drush_set_error('DRUSH_PM_DISABLE_EXTENSION_ISSUE', dt('There was a problem disabling !extension.', array('!extension' => implode(',', $problem_extensions)))); - } -} - -/** - * Command callback. Uninstall one or more modules. - */ -function _drush_pm_uninstall($modules) { - drush_include_engine('drupal', 'environment'); - $module_info = drush_get_modules(); - $required = drush_drupal_required_modules($module_info); - - // Discards modules which are enabled, not found or already uninstalled. - foreach ($modules as $key => $module) { - if (!isset($module_info[$module])) { - // The module does not exist in the system. - unset($modules[$key]); - drush_log(dt('Module !module was not found and will not be uninstalled.', array('!module' => $module)), LogLevel::WARNING); - } - else if ($module_info[$module]->status) { - // The module is enabled. - unset($modules[$key]); - drush_log(dt('!module is not disabled. Use `pm-disable` command before `pm-uninstall`.', array('!module' => $module)), LogLevel::WARNING); - } - else if ($module_info[$module]->schema_version == -1) { // SCHEMA_UNINSTALLED - // The module is uninstalled. - unset($modules[$key]); - drush_log(dt('!module is already uninstalled.', array('!module' => $module)), LogLevel::OK); - } - else { - $dependents = array(); - foreach (drush_module_dependents(array($module), $module_info) as $dependent) { - if (!in_array($dependent, $required) && ($module_info[$dependent]->schema_version != -1)) { - $dependents[] = $dependent; - } - } - if (count($dependents)) { - drush_log(dt('To uninstall !module, the following modules must be uninstalled first: !required', array('!module' => $module, '!required' => implode(', ', $dependents))), LogLevel::ERROR); - unset($modules[$key]); - } - } - } - - // Inform the user which modules will finally be uninstalled. - if (empty($modules)) { - return drush_log(dt('There were no modules that could be uninstalled.'), LogLevel::OK); - } - else { - drush_print(dt('The following modules will be uninstalled: !modules', array('!modules' => implode(', ', $modules)))); - if(!drush_confirm(dt('Do you really want to continue?'))) { - return drush_user_abort(); - } - } - - // Uninstall the modules. - drush_module_uninstall($modules); - - // Inform the user of final status. - foreach ($modules as $module) { - drush_log(dt('!module was successfully uninstalled.', array('!module' => $module)), LogLevel::OK); - } -} - diff --git a/commands/core/drupal/pm_8.inc b/commands/core/drupal/pm_8.inc deleted file mode 100644 index d0d44b12c1..0000000000 --- a/commands/core/drupal/pm_8.inc +++ /dev/null @@ -1,86 +0,0 @@ - $extension)), LogLevel::WARNING); - } - elseif (in_array($extension, $required)) { - unset($extensions[$extension]); - $info = $extension_info[$extension]->info; - $explanation = !empty($info['explanation']) ? ' ' . dt('Reason: !explanation.', array('!explanation' => strip_tags($info['explanation']))) : ''; - drush_log(dt('!extension is a required extension and can\'t be uninstalled.', array('!extension' => $extension)) . $explanation, LogLevel::OK); - } - elseif (!$extension_info[$extension]->status) { - unset($extensions[$extension]); - drush_log(dt('!extension is already uninstalled.', array('!extension' => $extension)), LogLevel::OK); - } - elseif (drush_extension_get_type($extension_info[$extension]) == 'module') { - // Add installed dependencies to the list of modules to uninstall. - foreach (drush_module_dependents(array($extension), $extension_info) as $dependent) { - // Check if this dependency is not required, already enabled, and not already already in the list of modules to uninstall. - if (!in_array($dependent, $required) && ($extension_info[$dependent]->status) && !in_array($dependent, $extensions)) { - $extensions[] = $dependent; - } - } - } - } - - // Discard default theme. - $default_theme = drush_theme_get_default(); - if (in_array($default_theme, $extensions)) { - unset($extensions[$default_theme]); - drush_log(dt('!theme is the default theme and can\'t be uninstalled.', array('!theme' => $default_theme)), LogLevel::OK); - } - - // Inform the user which extensions will finally be disabled. - if (empty($extensions)) { - return drush_log(dt('There were no extensions that could be uninstalled.'), LogLevel::OK); - } - else { - drush_print(dt('The following extensions will be uninstalled: !extensions', array('!extensions' => implode(', ', $extensions)))); - if(!drush_confirm(dt('Do you really want to continue?'))) { - return drush_user_abort(); - } - } - - // Classify extensions in themes and modules. - $modules = array(); - $themes = array(); - drush_pm_classify_extensions($extensions, $modules, $themes, $extension_info); - - drush_module_uninstall($modules); - drush_theme_uninstall($themes); - - // Inform the user of final status. - foreach ($extensions as $extension) { - drush_log(dt('!extension was successfully uninstalled.', array('!extension' => $extension)), LogLevel::OK); - } -} diff --git a/commands/pm/download.pm.inc b/commands/pm/download.pm.inc deleted file mode 100644 index 000d96c874..0000000000 --- a/commands/pm/download.pm.inc +++ /dev/null @@ -1,396 +0,0 @@ - $destination))); - if (!drush_get_context('DRUSH_SIMULATE')) { - if (drush_confirm(dt('Would you like to create it?'))) { - drush_mkdir($destination, TRUE); - } - if (!is_dir($destination)) { - return drush_set_error('DRUSH_PM_NO_DESTINATION', dt('Unable to create destination directory !destination.', array('!destination' => $destination))); - } - } - } - if (!is_writable($destination)) { - return drush_set_error('DRUSH_PM_NO_DESTINATION', dt('Destination directory !destination is not writable.', array('!destination' => $destination))); - } - // Ignore --use-site-dir, if given. - if (drush_get_option('use-site-dir', FALSE)) { - drush_set_option('use-site-dir', FALSE); - } - } - - // Validate --variant or enforce a sane default. - $variant = drush_get_option('variant', FALSE); - if ($variant) { - $variants = array('full', 'projects', 'profile-only'); - if (!in_array($variant, $variants)) { - return drush_set_error('DRUSH_PM_PROFILE_INVALID_VARIANT', dt('Invalid variant !variant. Valid values: !variants.', array('!variant' => $variant, '!variants' => implode(', ', $variants)))); - } - } - // 'full' and 'projects' variants are only valid for wget package handler. - $package_handler = drush_get_option('package-handler', 'wget'); - if (($package_handler != 'wget') && ($variant != 'profile-only')) { - $new_variant = 'profile-only'; - if ($variant) { - drush_log(dt('Variant !variant is incompatible with !ph package-handler.', array('!variant' => $variant, '!ph' => $package_handler)), LogLevel::WARNING); - } - } - // If we are working on a drupal root, full variant is not an option. - else if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_ROOT) { - if ((!$variant) || (($variant == 'full') && (!isset($new_variant)))) { - $new_variant = 'projects'; - } - if ($variant == 'full') { - drush_log(dt('Variant full is not a valid option within a Drupal root.'), LogLevel::WARNING); - } - } - - if (isset($new_variant)) { - drush_set_option('variant', $new_variant); - if ($variant) { - drush_log(dt('Switching to --variant=!variant.', array('!variant' => $new_variant)), LogLevel::OK); - } - } -} - -/** - * Command callback. Download Drupal core or any project. - */ -function drush_pm_download() { - $release_info = drush_get_engine('release_info'); - - if (!$requests = pm_parse_arguments(func_get_args(), FALSE)) { - $requests = array('drupal'); - } - - // Pick cli options. - $status_url = drush_get_option('source', ReleaseInfo::DEFAULT_URL); - $restrict_to = drush_get_option('dev', ''); - $select = drush_get_option('select', 'auto'); - $all = drush_get_option('all', FALSE); - // If we've bootstrapped a Drupal site and the user may have the chance - // to select from a list of filtered releases, we want to pass - // the installed project version, if any. - $projects = array(); - if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_FULL) { - if (!$all and in_array($select, array('auto', 'always'))) { - $projects = drush_get_projects(); - } - } - - // Get release history for each request and download the project. - foreach ($requests as $request) { - $request = pm_parse_request($request, $status_url, $projects); - $version = isset($projects[$request['name']]) ? $projects[$request['name']]['version'] : NULL; - $release = $release_info->selectReleaseBasedOnStrategy($request, $restrict_to, $select, $all, $version); - if ($release == FALSE) { - // Stop working on the first failure. Return silently on user abort. - if (drush_get_context('DRUSH_USER_ABORT', FALSE)) { - return FALSE; - } - // Signal that the command failed for all other problems. - return drush_set_error('DRUSH_DOWNLOAD_FAILED', dt("Could not download requested project(s).")); - } - $request['version'] = $release['version']; - - $project_release_info = $release_info->get($request); - $request['project_type'] = $project_release_info->getType(); - - // Determine the name of the directory that will contain the project. - // We face here all the assymetries to make it smooth for package handlers. - // For Drupal core: --drupal-project-rename or drupal-x.y - if (($request['project_type'] == 'core') || - (($request['project_type'] == 'profile') && (drush_get_option('variant', 'full') == 'full'))) { - // Avoid downloading core into existing core. - if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_ROOT) { - if (strpos(realpath(drush_get_option('destination')), DRUPAL_ROOT) !== FALSE) { - return drush_set_error('DRUSH_PM_DOWNLOAD_TRANSLATIONS_FORBIDDEN', dt('It\'s forbidden to download !project core into an existing core.', array('!project' => $request['name']))); - } - } - - if ($rename = drush_get_option('drupal-project-rename', FALSE)) { - if ($rename === TRUE) { - $request['project_dir'] = $request['name']; - } - else { - $request['project_dir'] = $rename; - } - } - else { - // Set to drupal-x.y, the expected name for .tar.gz contents. - // Explicitly needed for cvs package handler. - $request['project_dir'] = strtolower(strtr($release['name'], ' ', '-')); - } - } - // For the other project types we want the project name. Including core - // variant for profiles. Note those come with drupal-x.y in the .tar.gz. - else { - $request['project_dir'] = $request['name']; - } - - // Download the project to a temporary location. - drush_log(dt('Downloading project !name ...', array('!name' => $request['name']))); - $request['full_project_path'] = package_handler_download_project($request, $release); - if (!$request['full_project_path']) { - // Delete the cached update service file since it may be invalid. - $release_info->clearCached($request); - drush_log(dt('Error downloading !name', array('!name' => $request['name']), LogLevel::ERROR)); - continue; - } - - // Determine the install location for the project. User provided - // --destination has preference. - $destination = drush_get_option('destination'); - if (!empty($destination)) { - if (!file_exists($destination)) { - drush_mkdir($destination); - } - $request['project_install_location'] = realpath($destination); - } - else { - $request['project_install_location'] = _pm_download_destination($request['project_type']); - } - - // If user did not provide --destination, then call the - // download-destination-alter hook to give the chance to any commandfiles - // to adjust the install location or abort it. - if (empty($destination)) { - $result = drush_command_invoke_all_ref('drush_pm_download_destination_alter', $request, $release); - if (array_search(FALSE, $result, TRUE) !== FALSE) { - return FALSE; - } - } - - // Load version control engine and detect if (the parent directory of) the - // project install location is under a vcs. - if (!$version_control = drush_pm_include_version_control($request['project_install_location'])) { - continue; - } - - $request['project_install_location'] .= '/' . $request['project_dir']; - - if ($version_control->engine == 'backup') { - // Check if install location already exists. - if (is_dir($request['project_install_location'])) { - if (drush_confirm(dt('Install location !location already exists. Do you want to overwrite it?', array('!location' => $request['project_install_location'])))) { - drush_delete_dir($request['project_install_location'], TRUE); - } - else { - drush_log(dt("Skip installation of !project to !dest.", array('!project' => $request['name'], '!dest' => $request['project_install_location'])), LogLevel::WARNING); - continue; - } - } - } - else { - // Find and unlink all files but the ones in the vcs control directories. - $skip_list = array('.', '..'); - $skip_list = array_merge($skip_list, drush_version_control_reserved_files()); - drush_scan_directory($request['project_install_location'], '/.*/', $skip_list, 'unlink', TRUE, 'filename', 0, TRUE); - } - - // Copy the project to the install location. - if (drush_op('_drush_recursive_copy', $request['full_project_path'], $request['project_install_location'])) { - drush_log(dt("Project !project (!version) downloaded to !dest.", array('!project' => $request['name'], '!version' => $release['version'], '!dest' => $request['project_install_location'])), LogLevel::SUCCESS); - // Adjust full_project_path to the final project location. - $request['full_project_path'] = $request['project_install_location']; - - // If the version control engine is a proper vcs we also need to remove - // orphan directories. - if ($version_control->engine != 'backup') { - $empty_dirs = drush_find_empty_directories($request['full_project_path'], $version_control->reserved_files()); - foreach ($empty_dirs as $empty_dir) { - // Some VCS files are read-only on Windows (e.g., .svn/entries). - drush_delete_dir($empty_dir, TRUE); - } - } - - // Post download actions. - package_handler_post_download($request, $release); - drush_command_invoke_all('drush_pm_post_download', $request, $release); - $version_control->post_download($request); - - // Print release notes if --notes option is set. - if (drush_get_option('notes') && !drush_get_context('DRUSH_PIPE')) { - $project_release_info->getReleaseNotes($release['version'], FALSE); - } - - // Inform the user about available modules a/o themes in the downloaded project. - drush_pm_extensions_in_project($request); - } - else { - // We don't `return` here in order to proceed with downloading additional projects. - drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt("Project !project (!version) could not be downloaded to !dest.", array('!project' => $request['name'], '!version' => $release['version'], '!dest' => $request['project_install_location']))); - } - -// @todo - bring back when porting to Annotated. - // Notify about this project. -// if (NotifyCommands::isAllowed('pm-download', $commandData)) { -// $msg = dt('Project !project (!version) downloaded to !install.', array( -// '!project' => $name, -// '!version' => $release['version'], -// '!install' => $request['project_install_location'], -// )); -// NotifyCommands::shutdownSend($msg), $commandData); -// } - } -} - -/** - * Implementation of hook_drush_pm_download_destination_alter(). - * - * Built-in download-destination-alter hook. This particular version of - * the hook will move modules that contain only Drush commands to - * /usr/share/drush/commands if it exists, or $HOME/.drush if the - * site-wide location does not exist. - */ -function pm_drush_pm_download_destination_alter(&$request, $release) { - // A module is a pure Drush command if it has no .info.yml (8+) and contains no - // .drush.inc files. Skip this test for Drush itself, though; we do - // not want to download Drush to the ~/.drush folder. - if (in_array($request['project_type'], array('module', 'utility')) && ($request['name'] != 'drush')) { - $drush_command_files = drush_scan_directory($request['full_project_path'], '/.*\.drush.inc/'); - if (!empty($drush_command_files)) { - $pattern = drush_drupal_major_version() >= 8 ? '/.*\.info/' : '/.*\.module/'; - $module_files = drush_scan_directory($request['full_project_path'], $pattern); - if (empty($module_files)) { - $install_dir = drush_get_context('DRUSH_SITE_WIDE_COMMANDFILES'); - if (!is_dir($install_dir) || !is_writable($install_dir)) { - $install_dir = drush_get_context('DRUSH_PER_USER_CONFIGURATION'); - } - // Make the .drush dir if it does not already exist. - if (!is_dir($install_dir)) { - drush_mkdir($install_dir, FALSE); - } - // Change the location if the mkdir worked. - if (is_dir($install_dir)) { - $request['project_install_location'] = $install_dir; - } - } - // We need to clear the Drush commandfile cache so that - // our newly-downloaded Drush extension commandfiles can be found. - drush_cache_clear_all(); - } - } -} - -/** - * Determines a candidate destination directory for a particular site path. - * - * Optionally attempts to create the directory. - * - * @return String the candidate destination if it exists. - */ -function _pm_download_destination_lookup($type, $drupal_root, $sitepath, $create = FALSE) { - // Profiles in Drupal < 8 - if (($type == 'profile') && (drush_drupal_major_version() < 8)) { - $destination = 'profiles'; - } - // Type: module, theme or profile. - else { - if ($type == 'theme engine') { - $destination = 'themes/engines'; - } else { - $destination = $type . 's'; - } - // Prefer /contrib if it exists. - if ($sitepath) { - $destination = $sitepath . '/' . $destination; - } - $contrib = $destination . '/contrib'; - if (is_dir($contrib)) { - $destination = $contrib; - } - } - if ($create) { - drush_log(dt('Attempting to create destination directory at !dir', array('!dir' => $destination))); - drush_mkdir($destination, TRUE); - } - if (is_dir($destination)) { - drush_log(dt('Using destination directory !dir', array('!dir' => $destination))); - return $destination; - } - drush_log(dt('Could not find destination directory at !dir', array('!dir' => $destination))); - return FALSE; -} - -/** - * Returns the best destination for a particular download type we can find. - * - * It is based on the project type and drupal and site contexts. - */ -function _pm_download_destination($type) { - $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); - $site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT'); - $full_site_root = (empty($drupal_root) || empty($site_root)) ? '' : $drupal_root .'/'. $site_root; - $sitewide = empty($drupal_root) ? '' : $drupal_root . '/' . drush_drupal_sitewide_directory(); - - $in_site_directory = FALSE; - // Check if we are running within the site directory. - if (strpos(realpath(drush_cwd()), realpath($full_site_root)) !== FALSE || (drush_get_option('use-site-dir', FALSE))) { - $in_site_directory = TRUE; - } - - $destination = ''; - if ($type != 'core') { - // Attempt 1: If we are in a specific site directory, and the destination - // directory already exists, then we use that. - if (empty($destination) && $site_root && $in_site_directory) { - $create_dir = drush_get_option('use-site-dir', FALSE); - $destination = _pm_download_destination_lookup($type, $drupal_root, $full_site_root, $create_dir); - } - // Attempt 2: If the destination directory already exists for - // the sitewide directory, use that. - if (empty($destination) && $drupal_root) { - $destination = _pm_download_destination_lookup($type, $drupal_root, $sitewide); - } - // Attempt 3: If a specific (non default) site directory exists and - // the sitewide directory does not exist, then create destination - // in the site specific directory. - if (empty($destination) && $site_root && $site_root !== 'sites/default' && is_dir($full_site_root) && !is_dir($sitewide)) { - $destination = _pm_download_destination_lookup($type, $drupal_root, $full_site_root, TRUE); - } - // Attempt 4: If sitewide directory exists, then create destination there. - if (empty($destination) && is_dir($sitewide)) { - $destination = _pm_download_destination_lookup($type, $drupal_root, $sitewide, TRUE); - } - // Attempt 5: If site directory exists (even default), then create - // destination in that directory. - if (empty($destination) && $site_root && is_dir($full_site_root)) { - $destination = _pm_download_destination_lookup($type, $drupal_root, $full_site_root, TRUE); - } - } - // Attempt 6: If we didn't find a valid directory yet (or we somehow found - // one that doesn't exist) we always fall back to the current directory. - if (empty($destination) || !is_dir($destination)) { - $destination = drush_cwd(); - } - - return $destination; -} diff --git a/commands/pm/package_handler/git_drupalorg.inc b/commands/pm/package_handler/git_drupalorg.inc deleted file mode 100644 index e418a77ae9..0000000000 --- a/commands/pm/package_handler/git_drupalorg.inc +++ /dev/null @@ -1,275 +0,0 @@ -=1.7 - // (avoid drush_shell_exec because we want to run this even in --simulated mode.) - $success = exec('git --version', $git); - $git_version_array = explode(" ", $git[0]); - $git_version = $git_version_array[2]; - - drush_set_context('DRUSH_DEBUG', $debug); - if (!$success) { - return drush_set_error('DRUSH_SHELL_COMMAND_NOT_FOUND', dt('git executable not found.')); - } elseif ($git_version < '1.7') { - return drush_set_error('GIT_VERSION_UNSUPPORTED', dt('Your git version !git_version is not supported; please upgrade to git 1.7 or later.', array('!git_version' => $git_version))); - } - // Check git_deploy is enabled. Only for bootstrapped sites. - if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_FULL) { - drush_include_engine('drupal', 'environment'); - if (!drush_get_option('gitinfofile') && !drush_module_exists('git_deploy')) { - drush_log(dt('git package handler needs git_deploy module enabled to work properly.'), LogLevel::WARNING); - } - } - - return TRUE; -} - -/** - * Download a project. - * - * @param $request - * The project array with name, base and full (final) paths. - * @param $release - * The release details array from drupal.org. - */ -function package_handler_download_project(&$request, $release) { - if ($username = drush_get_option('gitusername')) { - // Uses SSH, which enables pushing changes back to git.drupal.org. - $repository = $username . '@git.drupal.org:project/' . $request['name'] . '.git'; - } - else { - $repository = 'git://git.drupal.org/project/' . $request['name'] . '.git'; - } - $request['repository'] = $repository; - $tag = $release['tag']; - - // If the --cache option was given, create a new git reference cache of the - // remote repository, or update the existing cache to fetch recent changes. - if (drush_get_option('cache') && ($cachedir = drush_directory_cache())) { - $gitcache = $cachedir . '/git'; - $projectcache = $gitcache . '/' . $request['name'] . '.git'; - drush_mkdir($gitcache); - // Setup a new cache, if we don't have this project yet. - if (!file_exists($projectcache)) { - // --mirror works similar to --bare, but retrieves all tags, local - // branches, remote branches, and any other refs (notes, stashes, etc). - // @see http://stackoverflow.com/questions/3959924 - $command = 'git clone --mirror'; - if (drush_get_context('DRUSH_VERBOSE')) { - $command .= ' --verbose --progress'; - } - $command .= ' %s %s'; - drush_shell_cd_and_exec($gitcache, $command, $repository, $request['name'] . '.git'); - } - // If we already have this project, update it to speed up subsequent clones. - else { - // A --mirror clone is fully synchronized with `git remote update` instead - // of `git fetch --all`. - // @see http://stackoverflow.com/questions/6150188 - drush_shell_cd_and_exec($projectcache, 'git remote update'); - } - $gitcache = $projectcache; - } - - // Clone the repo into a temporary path. - $clone_path = drush_tempdir(); - - $command = 'git clone'; - $command .= ' ' . drush_get_option('gitcloneparams'); - if (drush_get_option('cache')) { - $command .= ' --reference ' . drush_escapeshellarg($gitcache); - } - if (drush_get_context('DRUSH_VERBOSE')) { - $command .= ' --verbose --progress'; - } - $command .= ' ' . drush_escapeshellarg($repository); - $command .= ' ' . drush_escapeshellarg($clone_path); - if (!drush_shell_exec($command)) { - return drush_set_error('DRUSH_PM_GIT_CHECKOUT_PROBLEMS', dt('Unable to clone project !name from git.drupal.org.', array('!name' => $request['name']))); - } - - // Check if the 'tag' from the release feed is a tag or a branch. - // If the tag exists, git will return it - if (!drush_shell_cd_and_exec($clone_path, 'git tag -l ' . drush_escapeshellarg($tag))) { - return drush_set_error('DRUSH_PM_GIT_CHECKOUT_PROBLEMS', dt('Unable to clone project !name from git.drupal.org.', array('!name' => $request['name']))); - } - $output = drush_shell_exec_output(); - - if (isset($output[0]) && ($output[0] == $tag)) { - // If we want a tag, simply checkout it. The checkout will end up in - // "detached head" state. - $command = 'git checkout ' . drush_get_option('gitcheckoutparams'); - $command .= ' ' . drush_escapeshellarg($tag); - if (!drush_shell_cd_and_exec($clone_path, $command)) { - return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $request['name'] . ' from git.drupal.org.'); - } - } - else { - // Else, we want to checkout a branch. - // First check if we are not already in the correct branch. - if (!drush_shell_cd_and_exec($clone_path, 'git symbolic-ref HEAD')) { - return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $request['name'] . ' from git.drupal.org.'); - } - $output = drush_shell_exec_output(); - $current_branch = preg_replace('@^refs/heads/@', '', $output[0]); - - // If we are not on the correct branch already, switch to the correct one. - if ($current_branch != $tag) { - $command = 'git checkout'; - $command .= ' ' . drush_get_option('gitcheckoutparams'); - $command .= ' --track ' . drush_escapeshellarg('origin/' . $tag) . ' -b ' . drush_escapeshellarg($tag); - if (!drush_shell_cd_and_exec($clone_path, $command)) { - return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $request['name'] . ' from git.drupal.org.'); - } - } - } - - return $clone_path; -} - -/** - * Update a project (so far, only modules are supported). - * - * @param $request - * The project array with name, base and full (final) paths. - * @param $release - * The release details array from drupal.org. - */ -function package_handler_update_project($request, $release) { - drush_log('Updating project ' . $request['name'] . ' ...'); - - $commands = array(); - if ((!empty($release['version_extra'])) && ($release['version_extra'] == 'dev')) { - // Update the branch of the development repository. - $commands[] = 'git pull'; - $commands[] = drush_get_option('gitpullparams'); - } - else { - // Use a stable repository. - $commands[] = 'git fetch'; - $commands[] = drush_get_option('gitfetchparams'); - $commands[] = ';'; - $commands[] = 'git checkout'; - $commands[] = drush_get_option('gitcheckoutparams'); - $commands[] = $release['version']; - } - - if (!drush_shell_cd_and_exec($request['full_project_path'], implode(' ', $commands))) { - return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to update ' . $request['name'] . ' from git.drupal.org.'); - } - - return TRUE; -} - -/** - * Post download action. - * - * This action take place once the project is placed in its final location. - * - * Here we add the project as a git submodule. - */ -function package_handler_post_download($project, $release) { - if (drush_get_option('gitsubmodule', FALSE)) { - // Obtain the superproject path, then add as submodule. - if (drush_shell_cd_and_exec(dirname($project['full_project_path']), 'git rev-parse --show-toplevel')) { - $output = drush_shell_exec_output(); - $superproject = $output[0]; - // Add the downloaded project as a submodule of its git superproject. - $command = array(); - $command[] = 'git submodule add'; - $command[] = drush_get_option('gitsubmoduleaddparams'); - $command[] = $project['repository']; - // We need the submodule relative path. - $command[] = substr(realpath($project['full_project_path']), strlen(realpath($superproject)) + 1); - if (!drush_shell_cd_and_exec($superproject, implode(' ', $command))) { - return drush_set_error('DRUSH_PM_GIT_CHECKOUT_PROBLEMS', dt('Unable to add !name as a git submodule of !super.', array('!name' => $project['name'], '!super' => $superproject))); - } - } - else { - return drush_set_error('DRUSH_PM_GIT_SUBMODULE_PROBLEMS', dt('Unable to create !project as a git submodule: !dir is not in a Git repository.', array('!project' => $project['name'], '!dir' => dirname($project['full_project_path'])))); - } - } - - if (drush_get_option('gitinfofile', FALSE)) { - $matches = array(); - if (preg_match('/^(.+).x-dev$/', $release['version'], $matches)) { - $full_version = drush_pm_git_drupalorg_compute_rebuild_version($project['full_project_path'], $matches[1]); - } - else { - $full_version = $release['version']; - } - if (drush_shell_cd_and_exec(dirname($project['full_project_path']), 'git log -1 --pretty=format:%ct')) { - $output = drush_shell_exec_output(); - $datestamp = $output[0]; - } - else { - $datestamp = time(); - } - drush_pm_inject_info_file_metadata($project['full_project_path'], $project['name'], $full_version, $datestamp); - } - -} - -/** - * Helper function to compute the rebulid version string for a project. - * - * This does some magic in Git to find the latest release tag along - * the branch we're packaging from, count the number of commits since - * then, and use that to construct this fancy alternate version string - * which is useful for the version-specific dependency support in Drupal - * 7 and higher. - * - * NOTE: A similar function lives in git_deploy and in the drupal.org - * packaging script (see DrupalorgProjectPackageRelease.class.php inside - * drupalorg/drupalorg_project/plugins/release_packager). Any changes to the - * actual logic in here should probably be reflected in the other places. - * - * @param string $project_dir - * The full path to the root directory of the project to operate on. - * @param string $branch - * The branch that we're using for -dev. This should only include the - * core version, the dash, and the branch's major version (eg. '7.x-2'). - * - * @return string - * The full 'rebuild version string' in the given Git checkout. - */ -function drush_pm_git_drupalorg_compute_rebuild_version($project_dir, $branch) { - $rebuild_version = ''; - $branch_preg = preg_quote($branch); - - if (drush_shell_cd_and_exec($project_dir, 'git describe --tags')) { - $shell_output = drush_shell_exec_output(); - $last_tag = $shell_output[0]; - // Make sure the tag starts as Drupal formatted (for eg. - // 7.x-1.0-alpha1) and if we are on a proper branch (ie. not master) - // then it's on that branch. - if (preg_match('/^(?' . $branch_preg . '\.\d+(?:-[^-]+)?)(?-(?\d+-)g[0-9a-f]{7})?$/', $last_tag, $matches)) { - // If we found additional git metadata (in particular, number of commits) - // then use that info to build the version string. - if (isset($matches['gitextra'])) { - $rebuild_version = $matches['drupalversion'] . '+' . $matches['numberofcommits'] . 'dev'; - } - // Otherwise, the branch tip is pointing to the same commit as the - // last tag on the branch, in which case we use the prior tag and - // add '+0-dev' to indicate we're still on a -dev branch. - else { - $rebuild_version = $last_tag . '+0-dev'; - } - } - } - return $rebuild_version; -} diff --git a/commands/pm/package_handler/wget.inc b/commands/pm/package_handler/wget.inc deleted file mode 100644 index e263940c5b..0000000000 --- a/commands/pm/package_handler/wget.inc +++ /dev/null @@ -1,116 +0,0 @@ - to download link, so it is part of the cache key. Dev snapshots can then be cached forever. - $download_link = $release['download_link']; - if (strpos($release['download_link'], '-dev') !== FALSE) { - $download_link .= '?date=' . $release['date']; - } - // Cache for a year by default. - $cache_duration = (drush_get_option('cache', TRUE)) ? 86400*365 : 0; - - // Prepare download path. On Windows file name cannot contain '?'. - // See http://drupal.org/node/1782444 - $filename = str_replace('?', '_', basename($download_link)); - $download_path = drush_tempdir() . '/' . $filename; - - // Download the tarball. - $download_path = drush_download_file($download_link, $download_path, $cache_duration); - if ($download_path || drush_get_context('DRUSH_SIMULATE')) { - drush_log(dt('Downloading !filename was successful.', array('!filename' => $filename))); - } - else { - return drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt('Unable to download !project to !path from !url.', array('!project' => $request['name'], '!path' => $download_path, '!url' => $download_link))); - } - - // Check Md5 hash. - if (!drush_get_option('no-md5')) { - if (drush_op('md5_file', $download_path) !== $release['mdhash'] && !drush_get_context('DRUSH_SIMULATE')) { - drush_delete_dir(drush_download_file_name($download_link, TRUE)); - return drush_set_error('DRUSH_PM_FILE_CORRUPT', dt('File !filename is corrupt (wrong md5 checksum).', array('!filename' => $filename))); - } - else { - drush_log(dt('Md5 checksum of !filename verified.', array('!filename' => $filename))); - } - } - - // Extract the tarball in place and return the full path to the untarred directory. - $download_base = dirname($download_path); - if (!$tar_file_list = drush_tarball_extract($download_path, $download_base, TRUE)) { - // An error has been logged. - return FALSE; - } - $tar_directory = drush_trim_path($tar_file_list[0]); - - return $download_base . '/' . $tar_directory; -} - -/** - * Update a project. - * - * @return bool - * Success or failure. An error message will be logged. - */ -function package_handler_update_project(&$request, $release) { - $download_path = package_handler_download_project($request, $release); - if ($download_path) { - return drush_move_dir($download_path, $request['full_project_path']); - } - else { - return FALSE; - } -} - -/** - * Post download action. - * - * This action take place once the project is placed in its final location. - */ -function package_handler_post_download($project) { -} diff --git a/commands/pm/pm.drush.inc b/commands/pm/pm.drush.inc deleted file mode 100644 index 0ce47a6d6e..0000000000 --- a/commands/pm/pm.drush.inc +++ /dev/null @@ -1,1334 +0,0 @@ - 'Download projects from drupal.org or other sources.', - 'examples' => array( - 'drush dl drupal' => 'Download latest recommended release of Drupal core.', - 'drush dl drupal-7.x' => 'Download latest 7.x development version of Drupal core.', - 'drush dl drupal-6' => 'Download latest recommended release of Drupal 6.x.', - 'drush dl cck zen' => 'Download latest versions of CCK and Zen projects.', - 'drush dl og-1.3' => 'Download a specfic version of Organic groups module for my version of Drupal.', - 'drush dl diff-6.x-2.x' => 'Download a specific development branch of diff module for a specific Drupal version.', - 'drush dl views --select' => 'Show a list of recent releases of the views project, prompt for which one to download.', - 'drush dl webform --dev' => 'Download the latest dev release of webform.', - 'drush dl webform --cache' => 'Download webform. Fetch and populate the download cache as needed.', - ), - 'arguments' => array( - 'projects' => 'A comma delimited list of drupal.org project names, with optional version. Defaults to \'drupal\'', - ), - 'options' => array( - 'destination' => array( - 'description' => 'Path to which the project will be copied. If you\'re providing a relative path, note it is relative to the drupal root (if bootstrapped).', - 'example-value' => 'path', - ), - 'use-site-dir' => 'Force to use the site specific directory. It will create the directory if it doesn\'t exist. If --destination is also present this option will be ignored.', - 'notes' => 'Show release notes after each project is downloaded.', - 'variant' => array( - 'description' => "Only useful for install profiles. Possible values: 'full', 'projects', 'profile-only'.", - 'example-value' => 'full', - ), - 'select' => "Select the version to download interactively from a list of available releases.", - 'drupal-project-rename' => 'Alternate name for "drupal-x.y" directory when downloading Drupal project. Defaults to "drupal".', - 'default-major' => array( - 'description' => 'Specify the default major version of modules to download when there is no bootstrapped Drupal site. Defaults to "8".', - 'example-value' => '7', - ), - 'skip' => 'Skip automatic downloading of libraries (c.f. devel).', - 'pipe' => 'Returns a list of the names of the extensions (modules and themes) contained in the downloaded projects.', - ), - 'bootstrap' => DRUSH_BOOTSTRAP_MAX, - 'aliases' => array('dl'), - 'engines' => array( - 'version_control', - 'package_handler', - 'release_info', - ), - ); - return $items; -} - -/** - * Sort callback function for sorting extensions. - * - * It will sort first by type, second by package and third by name. - */ -function _drush_pm_sort_extensions($a, $b) { - $a_type = drush_extension_get_type($a); - $b_type = drush_extension_get_type($b); - if ($a_type == 'module' && $b_type == 'theme') { - return -1; - } - if ($a_type == 'theme' && $b_type == 'module') { - return 1; - } - $cmp = strcasecmp($a->info['package'], $b->info['package']); - if ($cmp == 0) { - $cmp = strcasecmp($a->info['name'], $b->info['name']); - } - return $cmp; -} - -/** - * Calculate an extension status based on current status and schema version. - * - * @param $extension - * Object of a single extension info. - * - * @return - * String describing extension status. Values: enabled|disabled|not installed - */ -function drush_get_extension_status($extension) { - if ((drush_extension_get_type($extension) == 'module') && ($extension->schema_version == -1)) { - $status = "not installed"; - } - else { - $status = ($extension->status == 1)?'enabled':'disabled'; - } - - return $status; -} - -/** - * Classify extensions as modules, themes or unknown. - * - * @param $extensions - * Array of extension names, by reference. - * @param $modules - * Empty array to be filled with modules in the provided extension list. - * @param $themes - * Empty array to be filled with themes in the provided extension list. - */ -function drush_pm_classify_extensions(&$extensions, &$modules, &$themes, $extension_info) { - _drush_pm_expand_extensions($extensions, $extension_info); - foreach ($extensions as $extension) { - if (!isset($extension_info[$extension])) { - continue; - } - $type = drush_extension_get_type($extension_info[$extension]); - if ($type == 'module') { - $modules[$extension] = $extension; - } - else if ($type == 'theme') { - $themes[$extension] = $extension; - } - } -} - -/** - * Obtain an array of installed projects off the extensions available. - * - * A project is considered to be 'enabled' when any of its extensions is - * enabled. - * If any extension lacks project information and it is found that the - * extension was obtained from drupal.org's cvs or git repositories, a new - * 'vcs' attribute will be set on the extension. Example: - * $extensions[name]->vcs = 'cvs'; - * - * @param array $extensions - * Array of extensions as returned by drush_get_extensions(). - * - * @return - * Array of installed projects with info of version, status and provided - * extensions. - */ -function drush_get_projects(&$extensions = NULL) { - if (!isset($extensions)) { - $extensions = drush_get_extensions(); - } - $projects = array( - 'drupal' => array( - 'label' => 'Drupal', - 'version' => drush_drupal_version(), - 'type' => 'core', - 'extensions' => array(), - ) - ); - if (isset($extensions['system']->info['datestamp'])) { - $projects['drupal']['datestamp'] = $extensions['system']->info['datestamp']; - } - foreach ($extensions as $extension) { - $extension_name = drush_extension_get_name($extension); - $extension_path = drush_extension_get_path($extension); - - // Obtain the project name. It is not available in this cases: - // 1. the extension is part of drupal core. - // 2. the project was checked out from CVS/git and cvs_deploy/git_deploy - // is not installed. - // 3. it is not a project hosted in drupal.org. - if (empty($extension->info['project'])) { - if (isset($extension->info['version']) && ($extension->info['version'] == drush_drupal_version())) { - $project = 'drupal'; - } - else { - if (is_dir($extension_path . '/CVS') && (!drush_module_exists('cvs_deploy'))) { - $extension->vcs = 'cvs'; - drush_log(dt('Extension !extension is fetched from cvs. Ignoring.', array('!extension' => $extension_name)), LogLevel::DEBUG); - } - elseif (is_dir($extension_path . '/.git') && (!drush_module_exists('git_deploy'))) { - $extension->vcs = 'git'; - drush_log(dt('Extension !extension is fetched from git. Ignoring.', array('!extension' => $extension_name)), LogLevel::DEBUG); - } - continue; - } - } - else { - $project = $extension->info['project']; - } - - // Create/update the project in $projects with the project data. - if (!isset($projects[$project])) { - $projects[$project] = array( - // If there's an extension with matching name, pick its label. - // Otherwise use just the project name. We avoid $extension->label - // for the project label because the extension's label may have - // no direct relation with the project name. For example, - // "Text (text)" or "Number (number)" for the CCK project. - 'label' => isset($extensions[$project]) ? $extensions[$project]->label : $project, - 'type' => drush_extension_get_type($extension), - 'version' => $extension->info['version'], - 'status' => $extension->status, - 'extensions' => array(), - ); - if (isset($extension->info['datestamp'])) { - $projects[$project]['datestamp'] = $extension->info['datestamp']; - } - if (isset($extension->info['project status url'])) { - $projects[$project]['status url'] = $extension->info['project status url']; - } - } - else { - // If any of the extensions is enabled, consider the project is enabled. - if ($extension->status != 0) { - $projects[$project]['status'] = $extension->status; - } - } - $projects[$project]['extensions'][] = drush_extension_get_name($extension); - } - - // Obtain each project's path and try to provide a better label for ones - // with machine name. - $reserved = array('modules', 'sites', 'themes'); - foreach ($projects as $name => $project) { - if ($name == 'drupal') { - continue; - } - - // If this project has no human label, see if we can find - // one "main" extension whose label we could use. - if ($project['label'] == $name) { - // If there is only one extension, construct a label based on - // the extension name. - if (count($project['extensions']) == 1) { - $extension = $extensions[$project['extensions'][0]]; - $projects[$name]['label'] = $extension->info['name'] . ' (' . $name . ')'; - } - else { - // Make a list of all of the extensions in this project - // that do not depend on any other extension in this - // project. - $candidates = array(); - foreach ($project['extensions'] as $e) { - $has_project_dependency = FALSE; - if (isset($extensions[$e]->info['dependencies']) && is_array($extensions[$e]->info['dependencies'])) { - foreach ($extensions[$e]->info['dependencies'] as $dependent) { - if (in_array($dependent, $project['extensions'])) { - $has_project_dependency = TRUE; - } - } - } - if ($has_project_dependency === FALSE) { - $candidates[] = $extensions[$e]->info['name']; - } - } - // If only one of the modules is a candidate, use its name in the label - if (count($candidates) == 1) { - $projects[$name]['label'] = reset($candidates) . ' (' . $name . ')'; - } - } - } - - drush_log(dt('Obtaining !project project path.', array('!project' => $name)), LogLevel::DEBUG); - $path = _drush_pm_find_common_path($project['type'], $project['extensions']); - // Prevent from setting a reserved path. For example it may happen in a case - // where a module and a theme are declared as part of a same project. - // There's a special case, a project called "sites", this is the reason for - // the second condition here. - if ($path == '.' || (in_array(basename($path), $reserved) && !in_array($name, $reserved))) { - drush_log(dt('Error while trying to find the common path for enabled extensions of project !project. Extensions are: !extensions.', array('!project' => $name, '!extensions' => implode(', ', $project['extensions']))), LogLevel::ERROR); - } - else { - $projects[$name]['path'] = $path; - } - } - - return $projects; -} - -/** - * Helper function to find the common path for a list of extensions in the aim to obtain the project name. - * - * @param $project_type - * Type of project we're trying to find. Valid values: module, theme. - * @param $extensions - * Array of extension names. - */ -function _drush_pm_find_common_path($project_type, $extensions) { - // Select the first path as the candidate to be the common prefix. - $extension = array_pop($extensions); - while (!($path = drupal_get_path($project_type, $extension))) { - drush_log(dt('Unknown path for !extension !type.', array('!extension' => $extension, '!type' => $project_type)), LogLevel::WARNING); - $extension = array_pop($extensions); - } - - // If there's only one extension we are done. Otherwise, we need to find - // the common prefix for all of them. - if (count($extensions) > 0) { - // Iterate over the other projects. - while($extension = array_pop($extensions)) { - $path2 = drupal_get_path($project_type, $extension); - if (!$path2) { - drush_log(dt('Unknown path for !extension !type.', array('!extension' => $extension, '!type' => $project_type)), LogLevel::DEBUG); - continue; - } - // Option 1: same path. - if ($path == $path2) { - continue; - } - // Option 2: $path is a prefix of $path2. - if (strpos($path2, $path) === 0) { - continue; - } - // Option 3: $path2 is a prefix of $path. - if (strpos($path, $path2) === 0) { - $path = $path2; - continue; - } - // Option 4: no one is a prefix of the other. Find the common - // prefix by iteratively strip the rigthtmost piece of $path. - // We will iterate until a prefix is found or path = '.', that on the - // other hand is a condition theorically impossible to reach. - do { - $path = dirname($path); - if (strpos($path2, $path) === 0) { - break; - } - } while ($path != '.'); - } - } - - return $path; -} - -/** - * @} End of "defgroup extensions". - */ - -/** - * Sanitize user provided arguments to several pm commands. - * - * Return an array of arguments off a space and/or comma separated values. - */ -function pm_parse_arguments($args, $dashes_to_underscores = TRUE) { - $arguments = _convert_csv_to_array($args); - foreach ($arguments as $key => $argument) { - $argument = ($dashes_to_underscores) ? strtr($argument, '-', '_') : $argument; - } - return $arguments; -} - -/** - * Decompound a version string and returns major, minor, patch and extra parts. - * - * @see _pm_parse_version_compound() - * @see pm_parse_version() - * - * @param string $version - * A version string like X.Y-Z, X.Y.Z-W or a subset. - * - * @return array - * Array with major, patch and extra keys. - */ -function _pm_parse_version_decompound($version) { - $pattern = '/^(\d+)(?:.(\d+))?(?:\.(x|\d+))?(?:-([a-z0-9\.-]*))?(?:\+(\d+)-dev)?$/'; - - $matches = array(); - preg_match($pattern, $version, $matches); - - $parts = array( - 'major' => '', - 'minor' => '', - 'patch' => '', - 'extra' => '', - 'offset' => '', - ); - if (isset($matches[1])) { - $parts['major'] = $matches[1]; - if (isset($matches[2])) { - if (isset($matches[3]) && $matches[3] != '') { - $parts['minor'] = $matches[2]; - $parts['patch'] = $matches[3]; - } - else { - $parts['patch'] = $matches[2]; - } - } - if (!empty($matches[4])) { - $parts['extra'] = $matches[4]; - } - if (!empty($matches[5])) { - $parts['offset'] = $matches[5]; - } - } - - return $parts; -} - -/** - * Build a version string from an array of major, minor and extra parts. - * - * @see _pm_parse_version_decompound() - * @see pm_parse_version() - * - * @param array $parts - * Array of parts. - * - * @return string - * A Version string. - */ -function _pm_parse_version_compound($parts) { - $project_version = ''; - if ($parts['patch'] != '') { - $project_version = $parts['major']; - if ($parts['minor'] != '') { - $project_version = $project_version . '.' . $parts['minor']; - } - if ($parts['patch'] == 'x') { - $project_version = $project_version . '.x-dev'; - } - else { - $project_version = $project_version . '.' . $parts['patch']; - if ($parts['extra'] != '') { - $project_version = $project_version . '-' . $parts['extra']; - } - } - if ($parts['offset'] != '') { - $project_version = $project_version . '+' . $parts['offset'] . '-dev'; - } - } - - return $project_version; -} - -/** - * Parses a version string and returns its components. - * - * It parses both core and contrib version strings. - * - * Core (semantic versioning): - * - 8.0.0-beta3+252-dev - * - 8.0.0-beta2 - * - 8.0.x-dev - * - 8.1.x - * - 8.0.1 - * - 8 - * - * Core (classic drupal scheme): - * - 7.x-dev - * - 7.x - * - 7.33 - * - 7.34+3-dev - * - 7 - * - * Contrib: - * - 7.x-1.0-beta1+30-dev - * - 7.x-1.0-beta1 - * - 7.x-1.0+30-dev - * - 7.x-1.0 - * - 1.0-beta1 - * - 1.0 - * - 7.x-1.x - * - 7.x-1.x-dev - * - 1.x - * - * @see pm_parse_request() - * - * @param string $version - * A core or project version string. - * - * @param bool $is_core - * Whether this is a core version or a project version. - * - * @return array - * Version string in parts. - * Example for a contrib version (ex: 7.x-3.2-beta1): - * - version : Fully qualified version string. - * - drupal_version : Core compatibility version (ex: 7.x). - * - version_major : Major version (ex: 3). - * - version_minor : Minor version. Not applicable. Always empty. - * - version_patch : Patch version (ex: 2). - * - version_extra : Extra version (ex: beta1). - * - project_version : Project specific part of the version (ex: 3.2-beta1). - * - * Example for a core version (ex: 8.1.2-beta2 or 7.0-beta2): - * - version : Fully qualified version string. - * - drupal_version : Core compatibility version (ex: 8.x). - * - version_major : Major version (ex: 8). - * - version_minor : Minor version (ex: 1). Empty if not a semver. - * - version_patch : Patch version (ex: 2). - * - version_extra : Extra version (ex: beta2). - * - project_version : Same as 'version'. - */ -function pm_parse_version($version, $is_core = FALSE) { - $core_parts = _pm_parse_version_decompound($version); - - // If no major version, we have no version at all. Pick a default. - $drupal_version_default = drush_drupal_major_version(); - if ($core_parts['major'] == '') { - $core_parts['major'] = ($drupal_version_default) ? $drupal_version_default : drush_get_option('default-major', 8); - } - - if ($is_core) { - $project_version = _pm_parse_version_compound($core_parts); - $version_parts = array( - 'version' => $project_version, - 'drupal_version' => $core_parts['major'] . '.x', - 'project_version' => $project_version, - 'version_major' => $core_parts['major'], - 'version_minor' => $core_parts['minor'], - 'version_patch' => ($core_parts['patch'] == 'x') ? '' : $core_parts['patch'], - 'version_extra' => ($core_parts['patch'] == 'x') ? 'dev' : $core_parts['extra'], - 'version_offset' => $core_parts['offset'], - ); - } - else { - // If something as 7.x-1.0-beta1, the project specific version is - // in $version['extra'] and we need to parse it. - if (strpbrk($core_parts['extra'], '.-')) { - $nocore_parts = _pm_parse_version_decompound($core_parts['extra']); - $nocore_parts['offset'] = $core_parts['offset']; - $project_version = _pm_parse_version_compound($nocore_parts); - $version_parts = array( - 'version' => $core_parts['major'] . '.x-' . $project_version, - 'drupal_version' => $core_parts['major'] . '.x', - 'project_version' => $project_version, - 'version_major' => $nocore_parts['major'], - 'version_minor' => $core_parts['minor'], - 'version_patch' => ($nocore_parts['patch'] == 'x') ? '' : $nocore_parts['patch'], - 'version_extra' => ($nocore_parts['patch'] == 'x') ? 'dev' : $nocore_parts['extra'], - 'version_offset' => $core_parts['offset'], - ); - } - // At this point we have half a version and must decide if this is a drupal major or a project. - else { - // If working on a bootstrapped site, core_parts has the project version. - if ($drupal_version_default) { - $project_version = _pm_parse_version_compound($core_parts); - $version = ($project_version) ? $drupal_version_default . '.x-' . $project_version : ''; - $version_parts = array( - 'version' => $version, - 'drupal_version' => $drupal_version_default . '.x', - 'project_version' => $project_version, - 'version_major' => $core_parts['major'], - 'version_minor' => $core_parts['minor'], - 'version_patch' => ($core_parts['patch'] == 'x') ? '' : $core_parts['patch'], - 'version_extra' => ($core_parts['patch'] == 'x') ? 'dev' : $core_parts['extra'], - 'version_offset' => $core_parts['offset'], - ); - } - // Not working on a bootstrapped site, core_parts is core version. - else { - $version_parts = array( - 'version' => '', - 'drupal_version' => $core_parts['major'] . '.x', - 'project_version' => '', - 'version_major' => '', - 'version_minor' => '', - 'version_patch' => '', - 'version_extra' => '', - 'version_offset' => '', - ); - } - } - } - - return $version_parts; -} - -/** - * Parse out the project name and version and return as a structured array. - * - * @see pm_parse_version() - * - * @param string $request_string - * Project name with optional version. Examples: 'ctools-7.x-1.0-beta1' - * - * @return array - * Array with all parts of the request info. - */ -function pm_parse_request($request_string, $status_url = NULL, &$projects = array()) { - // Split $request_string in project name and version. Note that hyphens (-) - // are permitted in project names (ex: field-conditional-state). - // We use a regex to split the string. The pattern used matches a string - // starting with hyphen, followed by one or more numbers, any of the valid - // symbols in version strings (.x-) and a catchall for the rest of the - // version string. - $parts = preg_split('/-(?:([\d+\.x].*))?$/', $request_string, NULL, PREG_SPLIT_DELIM_CAPTURE); - - if (count($parts) == 1) { - // No version in the request string. - $project = $request_string; - $version = ''; - } - else { - $project = $parts[0]; - $version = $parts[1]; - } - - $is_core = ($project == 'drupal'); - $request = array( - 'name' => $project, - ) + pm_parse_version($version, $is_core); - - // Set the status url if provided or available in project's info file. - if ($status_url) { - $request['status url'] = $status_url; - } - elseif (!empty($projects[$project]['status url'])) { - $request['status url'] = $projects[$project]['status url']; - } - - return $request; -} - -/** - * @defgroup engines Engine types - * @{ - */ - -/** - * Implementation of hook_drush_engine_type_info(). - */ -function pm_drush_engine_type_info() { - return array( - 'package_handler' => array( - 'option' => 'package-handler', - 'description' => 'Determine how to fetch projects from update service.', - 'default' => 'wget', - 'options' => array( - 'cache' => 'Cache release XML and tarballs or git clones. Git clones use git\'s --reference option. Defaults to 1 for downloads, and 0 for git.', - ), - ), - 'release_info' => array( - 'add-options-to-command' => TRUE, - ), - 'update_status' => array( - 'option' => 'update-backend', - 'description' => 'Determine how to fetch update status information.', - 'default' => 'drush', - 'add-options-to-command' => TRUE, - 'options' => array( - 'update-backend' => 'Backend to obtain available updates.', - 'check-disabled' => 'Check for updates of disabled modules and themes.', - 'security-only' => 'Only update modules that have security updates available.', - ), - 'combine-help' => TRUE, - ), - 'version_control' => array( - 'option' => 'version-control', - 'default' => 'backup', - 'description' => 'Integrate with version control systems.', - ), - ); -} - -/** - * Implements hook_drush_engine_ENGINE_TYPE(). - * - * Package handler engine is used by pm-download and - * pm-updatecode commands to determine how to download/checkout - * new projects and acquire updates to projects. - */ -function pm_drush_engine_package_handler() { - return array( - 'wget' => array( - 'description' => 'Download project packages using wget or curl.', - 'options' => array( - 'no-md5' => 'Skip md5 validation of downloads.', - ), - ), - 'git_drupalorg' => array( - 'description' => 'Use git.drupal.org to checkout and update projects.', - 'options' => array( - 'gitusername' => 'Your git username as shown on user/[uid]/edit/git. Typically, this is set this in drushrc.php. Omitting this prevents users from pushing changes back to git.drupal.org.', - 'gitsubmodule' => 'Use git submodules for checking out new projects. Existing git checkouts are unaffected, and will continue to (not) use submodules regardless of this setting.', - 'gitcheckoutparams' => 'Add options to the `git checkout` command.', - 'gitcloneparams' => 'Add options to the `git clone` command.', - 'gitfetchparams' => 'Add options to the `git fetch` command.', - 'gitpullparams' => 'Add options to the `git pull` command.', - 'gitinfofile' => 'Inject version info into each .info file.', - ), - 'sub-options' => array( - 'gitsubmodule' => array( - 'gitsubmoduleaddparams' => 'Add options to the `git submodule add` command.', - ), - ), - ), - ); -} - -/** - * Implements hook_drush_engine_ENGINE_TYPE(). - * - * Release info engine is used by several pm commands to obtain - * releases info from Drupal's update service or external sources. - */ -function pm_drush_engine_release_info() { - return array( - 'updatexml' => array( - 'description' => 'Drush release info engine for update.drupal.org and compatible services.', - 'options' => array( - 'source' => 'The base URL which provides project release history in XML. Defaults to http://updates.drupal.org/release-history.', - 'dev' => 'Work with development releases solely.', - ), - 'sub-options' => array( - 'cache' => array( - 'cache-duration-releasexml' => 'Expire duration (in seconds) for release XML. Defaults to 86400 (24 hours).', - ), - 'select' => array( - 'all' => 'Shows all available releases instead of a short list of recent releases.', - ), - ), - 'class' => 'Drush\UpdateService\ReleaseInfo', - ), - ); -} - -/** - * Implements hook_drush_engine_ENGINE_TYPE(). - * - * Update status engine is used to check available updates for - * the projects in a Drupal site. - */ -function pm_drush_engine_update_status() { - return array( - 'drupal' => array( - 'description' => 'Check available updates with update.module.', - 'drupal dependencies' => array('update'), - 'class' => 'Drush\UpdateService\StatusInfoDrupal', - ), - 'drush' => array( - 'description' => 'Check available updates without update.module.', - 'class' => 'Drush\UpdateService\StatusInfoDrush', - ), - ); -} - -/** - * Implements hook_drush_engine_ENGINE_TYPE(). - * - * Integration with VCS in order to easily commit your changes to projects. - */ -function pm_drush_engine_version_control() { - return array( - 'backup' => array( - 'description' => 'Backup all project files before updates.', - 'options' => array( - 'no-backup' => 'Do not perform backups. WARNING: Will result in non-core files/dirs being deleted (e.g. .git)', - 'backup-dir' => 'Specify a directory to backup projects into. Defaults to drush-backups within the home directory of the user running the command. It is forbidden to specify a directory inside your drupal root.', - ), - ), - 'bzr' => array( - 'signature' => 'bzr root %s', - 'description' => 'Quickly add/remove/commit your project changes to Bazaar.', - 'options' => array( - 'bzrsync' => 'Automatically add new files to the Bazaar repository and remove deleted files. Caution.', - 'bzrcommit' => 'Automatically commit changes to Bazaar repository. You must also use the --bzrsync option.', - ), - 'sub-options' => array( - 'bzrcommit' => array( - 'bzrmessage' => 'Override default commit message which is: Drush automatic commit. Project Command: ', - ), - ), - 'examples' => array( - 'drush dl cck --version-control=bzr --bzrsync --bzrcommit' => 'Download the cck project and then add it and commit it to Bazaar.' - ), - ), - 'svn' => array( - 'signature' => 'svn info %s', - 'description' => 'Quickly add/remove/commit your project changes to Subversion.', - 'options' => array( - 'svnsync' => 'Automatically add new files to the SVN repository and remove deleted files. Caution.', - 'svncommit' => 'Automatically commit changes to SVN repository. You must also using the --svnsync option.', - 'svnstatusparams' => "Add options to the 'svn status' command", - 'svnaddparams' => 'Add options to the `svn add` command', - 'svnremoveparams' => 'Add options to the `svn remove` command', - 'svnrevertparams' => 'Add options to the `svn revert` command', - 'svncommitparams' => 'Add options to the `svn commit` command', - ), - 'sub-options' => array( - 'svncommit' => array( - 'svnmessage' => 'Override default commit message which is: Drush automatic commit: ', - ), - ), - 'examples' => array( - 'drush [command] cck --svncommitparams=\"--username joe\"' => 'Commit changes as the user \'joe\' (Quotes are required).' - ), - ), - ); -} - -/** - * @} End of "Engine types". - */ - -/** - * Interface for version control systems. - * We use a simple object layer because we conceivably need more than one - * loaded at a time. - */ -interface drush_version_control { - function pre_update(&$project); - function rollback($project); - function post_update($project); - function post_download($project); - static function reserved_files(); -} - -/** - * A simple factory function that tests for version control systems, in a user - * specified order, and returns the one that appears to be appropriate for a - * specific directory. - */ -function drush_pm_include_version_control($directory = '.') { - $engine_info = drush_get_engines('version_control'); - $version_controls = drush_get_option('version-control', FALSE); - // If no version control was given, use a list of defaults. - if (!$version_controls) { - // Backup engine is the last option. - $version_controls = array_reverse(array_keys($engine_info['engines'])); - } - else { - $version_controls = array($version_controls); - } - - // Find the first valid engine in the list, checking signatures if needed. - $engine = FALSE; - while (!$engine && count($version_controls)) { - $version_control = array_shift($version_controls); - if (isset($engine_info['engines'][$version_control])) { - if (!empty($engine_info['engines'][$version_control]['signature'])) { - drush_log(dt('Verifying signature for !vcs version control engine.', array('!vcs' => $version_control)), LogLevel::DEBUG); - if (drush_shell_exec($engine_info['engines'][$version_control]['signature'], $directory)) { - $engine = $version_control; - } - } - else { - $engine = $version_control; - } - } - } - if (!$engine) { - return drush_set_error('DRUSH_PM_NO_VERSION_CONTROL', dt('No valid version control or backup engine found (the --version-control option was set to "!version-control").', array('!version-control' => $version_control))); - } - - $instance = drush_include_engine('version_control', $engine); - return $instance; -} - -/** - * Update the locked status of all of the candidate projects - * to be updated. - * - * @param array &$projects - * The projects array from pm_updatecode. $project['locked'] will - * be set for every file where a persistent lockfile can be found. - * The 'lock' and 'unlock' operations are processed first. - * @param array $projects_to_lock - * A list of projects to create peristent lock files for - * @param array $projects_to_unlock - * A list of projects to clear the persistent lock on - * @param string $lock_message - * The reason the project is being locked; stored in the lockfile. - * - * @return array - * A list of projects that are locked. - */ -function drush_pm_update_lock(&$projects, $projects_to_lock, $projects_to_unlock, $lock_message = NULL) { - $locked_result = array(); - - // Warn about ambiguous lock / unlock values - if ($projects_to_lock == array('1')) { - $projects_to_lock = array(); - drush_log(dt('Ignoring --lock with no value.'), LogLevel::WARNING); - } - if ($projects_to_unlock == array('1')) { - $projects_to_unlock = array(); - drush_log(dt('Ignoring --unlock with no value.'), LogLevel::WARNING); - } - - // Log if we are going to lock or unlock anything - if (!empty($projects_to_unlock)) { - drush_log(dt('Unlocking !projects', array('!projects' => implode(',', $projects_to_unlock))), LogLevel::OK); - } - if (!empty($projects_to_lock)) { - drush_log(dt('Locking !projects', array('!projects' => implode(',', $projects_to_lock))), LogLevel::OK); - } - - $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); - foreach ($projects as $name => $project) { - $message = NULL; - if (isset($project['path'])) { - if ($name == 'drupal') { - $lockfile = $drupal_root . '/.drush-lock-update'; - } - else { - $lockfile = $drupal_root . '/' . $project['path'] . '/.drush-lock-update'; - } - - // Remove the lock file if the --unlock option was specified - if (((in_array($name, $projects_to_unlock)) || (in_array('all', $projects_to_unlock))) && (file_exists($lockfile))) { - drush_op('unlink', $lockfile); - } - - // Create the lock file if the --lock option was specified - if ((in_array($name, $projects_to_lock)) || (in_array('all', $projects_to_lock))) { - drush_op('file_put_contents', $lockfile, $lock_message != NULL ? $lock_message : "Locked via drush."); - // Note that the project is locked. This will work even if we are simulated, - // or if we get permission denied from the file_put_contents. - // If the lock is -not- simulated or transient, then the lock message will be - // read from the lock file below. - $message = drush_get_context('DRUSH_SIMULATE') ? 'Simulated lock.' : 'Transient lock.'; - } - - // If the persistent lock file exists, then mark the project as locked. - if (file_exists($lockfile)) { - $message = trim(file_get_contents($lockfile)); - } - } - - // If there is a message set, then mark the project as locked. - if (isset($message)) { - $projects[$name]['locked'] = !empty($message) ? $message : "Locked."; - $locked_result[$name] = $project; - } - } - - return $locked_result; -} - -/** - * Returns the path to the extensions cache file. - */ -function _drush_pm_extension_cache_file() { - return drush_get_context('DRUSH_PER_USER_CONFIGURATION') . "/drush-extension-cache.inc"; -} - -/** - * Load the extensions cache. - */ -function _drush_pm_get_extension_cache() { - $extension_cache = array(); - $cache_file = _drush_pm_extension_cache_file(); - - if (file_exists($cache_file)) { - include $cache_file; - } - if (!array_key_exists('extension-map', $extension_cache)) { - $extension_cache['extension-map'] = array(); - } - return $extension_cache; -} - -/** - * Lookup an extension in the extensions cache. - */ -function drush_pm_lookup_extension_in_cache($extension) { - $result = NULL; - $extension_cache = _drush_pm_get_extension_cache(); - if (!empty($extension_cache) && array_key_exists($extension, $extension_cache)) { - $result = $extension_cache[$extension]; - } - return $result; -} - -/** - * Persists extensions cache. - * - * #TODO# not implemented. - */ -function drush_pm_put_extension_cache($extension_cache) { -} - -/** - * Store extensions founds within a project in extensions cache. - */ -function drush_pm_cache_project_extensions($project, $found) { - $extension_cache = _drush_pm_get_extension_cache(); - foreach($found as $extension) { - // Simple cache does not handle conflicts - // We could keep an array of projects, and count - // how many times each one has been seen... - $extension_cache[$extension] = $project['name']; - } - drush_pm_put_extension_cache($extension_cache); -} - -/** - * Print out all extensions (modules/themes/profiles) found in specified project. - * - * Find .info.yml files in the project path and identify modules, themes and - * profiles. It handles two kind of projects: drupal core/profiles and - * modules/themes. - * It does nothing with theme engine projects. - */ -function drush_pm_extensions_in_project($project) { - // Mask for drush_scan_directory, to match .info.yml files. - $mask = $project['drupal_version'][0] >= 8 ? '/(.*)\.info\.yml$/' : '/(.*)\.info$/'; - - // Mask for drush_scan_directory, to avoid tests directories. - $nomask = array('.', '..', 'CVS', 'tests'); - - // Drupal core and profiles can contain modules, themes and profiles. - if (in_array($project['project_type'], array('core', 'profile'))) { - $found = array('profile' => array(), 'theme' => array(), 'module' => array()); - // Find all of the .info files - foreach (drush_scan_directory($project['full_project_path'], $mask, $nomask) as $filename => $info) { - // Extract extension name from filename. - $matches = array(); - preg_match($mask, $info->basename, $matches); - $name = $matches[1]; - - // Find the project type corresponding the .info file. - // (Only drupal >=7.x has .info for .profile) - $base = dirname($filename) . '/' . $name; - if (is_file($base . '.module')) { - $found['module'][] = $name; - } - else if (is_file($base . '.profile')) { - $found['profile'][] = $name; - } - else { - $found['theme'][] = $name; - } - } - // Special case: find profiles for drupal < 7.x (no .info) - if ($project['drupal_version'][0] < 7) { - foreach (drush_find_profiles($project['full_project_path']) as $filename => $info) { - $found['profile'][] = $info->name; - } - } - // Log results. - $msg = "Project !project contains:\n"; - $args = array('!project' => $project['name']); - foreach (array_keys($found) as $type) { - if ($count = count($found[$type])) { - $msg .= " - !count_$type !type_$type: !found_$type\n"; - $args += array("!count_$type" => $count, "!type_$type" => $type, "!found_$type" => implode(', ', $found[$type])); - if ($count > 1) { - $args["!type_$type"] = $type.'s'; - } - } - } - drush_log(dt($msg, $args), LogLevel::SUCCESS); - drush_print_pipe(call_user_func_array('array_merge', array_values($found))); - } - // Modules and themes can only contain other extensions of the same type. - elseif (in_array($project['project_type'], array('module', 'theme'))) { - $found = array(); - foreach (drush_scan_directory($project['full_project_path'], $mask, $nomask) as $filename => $info) { - // Extract extension name from filename. - $matches = array(); - preg_match($mask, $info->basename, $matches); - $found[] = $matches[1]; - } - // If there is only one module / theme in the project, only print out - // the message if is different than the project name. - if (count($found) == 1) { - if ($found[0] != $project['name']) { - $msg = "Project !project contains a !type named !found."; - } - } - // If there are multiple modules or themes in the project, list them all. - else { - $msg = "Project !project contains !count !types: !found."; - } - if (isset($msg)) { - drush_print(dt($msg, array('!project' => $project['name'], '!count' => count($found), '!type' => $project['project_type'], '!found' => implode(', ', $found)))); - } - drush_print_pipe($found); - // Cache results. - drush_pm_cache_project_extensions($project, $found); - } -} - -/** - * Return an array of empty directories. - * - * Walk a directory and return an array of subdirectories that are empty. Will - * return the given directory if it's empty. - * If a list of items to exclude is provided, subdirectories will be condidered - * empty even if they include any of the items in the list. - * - * @param string $dir - * Path to the directory to work in. - * @param array $exclude - * Array of files or directory to exclude in the check. - * - * @return array - * A list of directory paths that are empty. A directory is deemed to be empty - * if it only contains excluded files or directories. - */ -function drush_find_empty_directories($dir, $exclude = array()) { - // Skip files. - if (!is_dir($dir)) { - return array(); - } - $to_exclude = array_merge(array('.', '..'), $exclude); - $empty_dirs = array(); - $dir_is_empty = TRUE; - foreach (scandir($dir) as $file) { - // Skip excluded directories. - if (in_array($file, $to_exclude)) { - continue; - } - // Recurse into sub-directories to find potentially empty ones. - $subdir = $dir . '/' . $file; - $empty_dirs += drush_find_empty_directories($subdir, $exclude); - // $empty_dir will not contain $subdir, if it is a file or if the - // sub-directory is not empty. $subdir is only set if it is empty. - if (!isset($empty_dirs[$subdir])) { - $dir_is_empty = FALSE; - } - } - - if ($dir_is_empty) { - $empty_dirs[$dir] = $dir; - } - return $empty_dirs; -} - -/** - * Inject metadata into all .info files for a given project. - * - * @param string $project_dir - * The full path to the root directory of the project to operate on. - * @param string $project_name - * The project machine name (AKA shortname). - * @param string $version - * The version string to inject into the .info file(s). - * @param int $datestamp - * The datestamp of the last commit. - * - * @return boolean - * TRUE on success, FALSE on any failures appending data to .info files. - */ -function drush_pm_inject_info_file_metadata($project_dir, $project_name, $version, $datestamp) { - // `drush_drupal_major_version()` cannot be used here because this may be running - // outside of a Drupal context. - $yaml_format = substr($version, 0, 1) >= 8; - $pattern = preg_quote($yaml_format ? '.info.yml' : '.info'); - $info_files = drush_scan_directory($project_dir, '/.*' . $pattern . '$/'); - if (!empty($info_files)) { - // Construct the string of metadata to append to all the .info files. - if ($yaml_format) { - $info = _drush_pm_generate_info_yaml_metadata($version, $project_name, $datestamp); - } - else { - $info = _drush_pm_generate_info_ini_metadata($version, $project_name, $datestamp); - } - foreach ($info_files as $info_file) { - if (!drush_file_append_data($info_file->filename, $info)) { - return FALSE; - } - } - } - return TRUE; -} - -/** - * Generate version information for `.info` files in ini format. - * - * Taken with some modifications from: - * http://drupalcode.org/project/drupalorg.git/blob/refs/heads/6.x-3.x:/drupalorg_project/plugins/release_packager/DrupalorgProjectPackageRelease.class.php#l192 - */ -function _drush_pm_generate_info_ini_metadata($version, $project_name, $datestamp) { - $matches = array(); - $extra = ''; - if (preg_match('/^((\d+)\.x)-.*/', $version, $matches) && $matches[2] >= 6) { - $extra .= "\ncore = \"$matches[1]\""; - } - if (!drush_get_option('no-gitprojectinfo', FALSE)) { - $extra = "\nproject = \"$project_name\""; - } - $date = date('Y-m-d', $datestamp); - $info = <<= 6) { - $extra .= "\ncore: '$matches[1]'"; - } - if (!drush_get_option('no-gitprojectinfo', FALSE)) { - $extra = "\nproject: '$project_name'"; - } - $date = date('Y-m-d', $datestamp); - $info = <<prepare_backup_dir()) { - if ($project['project_type'] != 'core') { - $backup_target .= '/' . $project['project_type'] . 's'; - drush_mkdir($backup_target); - } - $backup_target .= '/'. $project['name']; - // Save for rollback or notifications. - $project['backup_target'] = $backup_target; - - // Move or copy to backup target based in package-handler. - if (drush_get_option('package-handler', 'wget') == 'wget') { - if (drush_move_dir($project['full_project_path'], $backup_target)) { - return TRUE; - } - } - // cvs or git. - elseif (drush_copy_dir($project['full_project_path'], $backup_target)) { - return TRUE; - } - return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('Failed to backup project directory !project to !backup_target', array('!project' => $project['full_project_path'], '!backup_target' => $backup_target))); - } - } - - /** - * Implementation of rollback(). - */ - public function rollback($project) { - if (drush_get_option('no-backup', FALSE)) { - return; - } - if (drush_move_dir($project['backup_target'], $project['full_project_path'], TRUE)) { - return drush_log(dt("Backups were restored successfully."), LogLevel::OK); - } - return drush_set_error('DRUSH_PM_BACKUP_ROLLBACK_FAILED', dt('Could not restore backup and rollback from failed upgrade. You will need to resolve manually.')); - } - - /** - * Implementation of post_update(). - */ - public function post_update($project) { - if (drush_get_option('no-backup', FALSE)) { - return; - } - if ($project['backup_target']) { - drush_log(dt("Backups were saved into the directory !backup_target.", array('!backup_target' => $project['backup_target'])), LogLevel::OK); - } - } - - /** - * Implementation of post_download(). - */ - public function post_download($project) { - // NOOP - } - - // Helper for pre_update. - public function prepare_backup_dir($subdir = NULL) { - return drush_prepare_backup_dir($subdir); - } - - public static function reserved_files() { - return array(); - } -} diff --git a/commands/pm/version_control/bzr.inc b/commands/pm/version_control/bzr.inc deleted file mode 100644 index 22bfb7a412..0000000000 --- a/commands/pm/version_control/bzr.inc +++ /dev/null @@ -1,137 +0,0 @@ - '.'); - } - $args = array_keys($items_to_test); - array_unshift($args, 'bzr status --short' . str_repeat(' %s', count($args))); - array_unshift($args, $project['full_project_path']); - if (call_user_func_array('drush_shell_cd_and_exec', $args)) { - $output = preg_grep('/^[\sRCP][\sNDKM][\s\*]/', drush_shell_exec_output()); - if (!empty($output)) { - return drush_set_error('DRUSH_PM_BZR_LOCAL_CHANGES', dt("The Bazaar working copy at !path appears to have uncommitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output)))); - } - } - else { - return drush_set_error('DRUSH_PM_BZR_NOT_FOUND', dt("Drush was unable to get the bzr status on !path. Check that you have Bazaar \ninstalled and that this directory is a Bazaar working copy.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output())))); - } - return TRUE; - } - - /** - * Implementation of rollback(). - */ - public function rollback($project) { - if (drush_shell_exec('bzr revert %s', $project['full_project_path'])) { - $output = drush_shell_exec_output(); - if (!empty($output)) { - return drush_set_error('DRUSH_PM_BZR_LOCAL_CHANGES', dt("The Bazaar working copy at !path appears to have uncommitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output)))); - } - } - else { - return drush_set_error('DRUSH_PM_BZR_NOT_FOUND', dt("Drush was unable to get the Bazaar status on !path. Check that you have Bazaar \ninstalled and that this directory is a Bazaar working copy.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output())))); - } - } - - /** - * Implementation of post_update(). - */ - public function post_update($project) { - if ($this->sync($project)) { - // Only attempt commit on a sucessful sync - $this->commit($project); - } - } - - /** - * Implementation of post_download(). - */ - public function post_download($project) { - if ($this->sync($project)) { - // Only attempt commit on a sucessful sync - $this->commit($project); - } - } - - /** - * Automatically add any unversioned files to Bazaar and remove any files - * that have been deleted on the file system - */ - private function sync($project) { - if (drush_get_option('bzrsync')) { - $errors = ''; - $root = array(); - if (drush_shell_exec('bzr status --short %s', $project['full_project_path'])) { - $output = drush_shell_exec_output(); - // All paths returned by bzr status are relative to the repository root. - if (drush_shell_exec('bzr root %s', $project['full_project_path'])) { - $root = drush_shell_exec_output(); - } - foreach ($output as $line) { - if (preg_match('/^\?\s+(.*)/', $line, $matches)) { - $path = $root[0] .'/'. $matches[1]; - if (!drush_shell_exec('bzr add --no-recurse %s', $path)) { - $errors .= implode("\n", drush_shell_exec_output()); - } - } - else if (preg_match('/^\s+D\s+(.*)/', $line, $matches)) { - $path = $root[0] .'/'. $matches[1]; - if (!drush_shell_exec('bzr remove %s', $path)) { - $errors .= implode("\n", drush_shell_exec_output()); - } - } - } - if (!empty($errors)) { - return drush_set_error('DRUSH_PM_BZR_SYNC_PROBLEMS', dt("Problems were encountered adding or removing files to/from Bazaar.\nThe specific errors are below:\n!errors", array('!errors' => $errors))); - } - } - else { - return drush_set_error('DRUSH_PM_BZR_NOT_FOUND', dt("Drush was unable to get the bzr status. Check that you have Bazaar \ninstalled and that the site is a Bazaar working copy.\nThe specific errors are below:\n!errors", array('!errors' => implode("\n", drush_shell_exec_output())))); - } - return TRUE; - } - } - - /** - * Automatically commit changes to the repository - */ - private function commit($project) { - if (drush_get_option('bzrcommit')) { - $message = drush_get_option('bzrmessage'); - if (empty($message)) { - $message = dt("Drush automatic commit.\nProject: @name @type\nCommand: @arguments", array('@name' => $project['name'], '@type' => $project['project_type'], '@arguments' => implode(' ', $_SERVER['argv']))); - } - if (drush_shell_exec('bzr commit --message=%s %s', $message, $project['full_project_path'])) { - drush_log(dt('Project committed to Bazaar successfully'), LogLevel::OK); - } - else { - drush_set_error('DRUSH_PM_BZR_COMMIT_PROBLEMS', dt("Problems were encountered committing your changes to Bazaar.\nThe specific errors are below:\n!errors", array('!errors' => implode("\n", drush_shell_exec_output())))); - } - } - else { - drush_print(dt("You should consider committing the new code to your Bazaar repository.\nIf this version becomes undesireable, use Bazaar to roll back.")); - } - } - - public static function reserved_files() { - return array('.bzr', '.bzrignore', '.bzrtags'); - } -} diff --git a/commands/pm/version_control/svn.inc b/commands/pm/version_control/svn.inc deleted file mode 100644 index 42aafa9a43..0000000000 --- a/commands/pm/version_control/svn.inc +++ /dev/null @@ -1,138 +0,0 @@ - $project['full_project_path'], '!output' => implode("\n", $output)))); - } - } - else { - return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn status on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output())))); - } - - // Check for incoming updates - $args = array_keys($items_to_test); - array_unshift($args, 'svn status -u '. drush_get_option('svnstatusparams') . str_repeat('%s ', count($args))); - array_unshift($args, $project['full_project_path']); - if (call_user_func_array('drush_shell_cd_and_exec', $args)) { - $output = preg_grep('/\*/', drush_shell_exec_output()); - if (!empty($output)) { - return drush_set_error('DRUSH_PM_SVN_REMOTE_CHANGES', dt("The SVN working copy at !path appears to be out of date with the repository (see below). Please run 'svn update' to pull down changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output)))); - } - } - else { - return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn remote status on !path. Check that you have connectivity to the repository.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output())))); - } - return TRUE; - } - - /** - * Implementation of rollback(). - */ - public function rollback($project) { - if (drush_shell_exec('svn revert '. drush_get_option('svnrevertparams') .' '. $project['full_project_path'])) { - $output = drush_shell_exec_output(); - if (!empty($output)) { - return drush_set_error('DRUSH_PM_SVN_LOCAL_CHANGES', dt("The SVN working copy at !path appears to have uncommitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output)))); - } - } - else { - return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn status on !path. Check that you have Subversion \ninstalled and that this directory is a subversion working copy.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output())))); - } - } - - /** - * Implementation of post_update(). - */ - public function post_update($project) { - if ($this->sync($project)) { - // Only attempt commit on a sucessful sync - $this->commit($project); - } - } - - /** - * Implementation of post_download(). - */ - public function post_download($project) { - if ($this->sync($project)) { - // Only attempt commit on a sucessful sync - $this->commit($project); - } - } - - /** - * Automatically add any unversioned files to Subversion and remove any files - * that have been deleted on the file system - */ - private function sync($project) { - if (drush_get_option('svnsync')) { - $errors = ''; - if (drush_shell_exec('svn status '. drush_get_option('svnstatusparams') .' '. $project['full_project_path'])) { - $output = drush_shell_exec_output(); - foreach ($output as $line) { - if (preg_match('/^\? *(.*)/', $line, $matches)) { - if (!drush_shell_exec('svn add '. drush_get_option('svnaddparams') .' '. $matches[1])) { - $errors .= implode("\n", drush_shell_exec_output()); - } - } - if (preg_match('/^\! *(.*)/', $line, $matches)) { - if (!drush_shell_exec('svn remove '. drush_get_option('svnremoveparams') .' '. $matches[1])) { - $errors .= implode("\n", drush_shell_exec_output()); - } - } - } - if (!empty($errors)) { - return drush_set_error('DRUSH_PM_SVN_SYNC_PROBLEMS', dt("Problems were encountered adding or removing files to/from this SVN working copy.\nThe specific errors are below:\n!errors", array('!errors' => $errors))); - } - } - else { - return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn status on !path. Check that you have Subversion \ninstalled and that this directory is a subversion working copy.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output())))); - } - return TRUE; - } - } - - /** - * Automatically commit changes to the repository - */ - private function commit($project) { - if (drush_get_option('svncommit')) { - $message = drush_get_option('svnmessage'); - if (empty($message)) { - $message = dt("Drush automatic commit: \n") . implode(' ', $_SERVER['argv']); - } - if (drush_shell_exec('svn commit '. drush_get_option('svncommitparams') .' -m "'. $message .'" '. $project['full_project_path'])) { - drush_log(dt('Project committed to Subversion successfully'), LogLevel::OK); - } - else { - drush_set_error('DRUSH_PM_SVN_COMMIT_PROBLEMS', dt("Problems were encountered committing your changes to Subversion.\nThe specific errors are below:\n!errors", array('!errors' => implode("\n", drush_shell_exec_output())))); - } - } - else { - drush_print(dt("You should consider committing the new code to your Subversion repository.\nIf this version becomes undesireable, use Subversion to roll back.")); - } - } - - public static function reserved_files() { - return array('.svn'); - } -} diff --git a/docs/output-formats.md b/docs/output-formats.md deleted file mode 100644 index 1dc37285c8..0000000000 --- a/docs/output-formats.md +++ /dev/null @@ -1,20 +0,0 @@ -Drush Output Formats -==================== - -Many Drush commands produce output that may be rendered in a variety of different ways using a pluggable formatting system. Drush commands that support output formats will show a --format option in their help text. The available formats are also listed in the help text, along with the default value for the format option. The list of formats shown is abbreviated; to see the complete list of available formats, run the help command with the --verbose option. - -The --pipe option is a quick, consistent way to get machine readable output from a command, in whatever way the command author thought was helpful. The --pipe option is equivalent to using --format=`` The pipe format will be shown in the options section of the command help, under the --pipe option. For historic reasons, --pipe also hides all log messages. - -To best understand how the various Drush output formatters work, it is best to first look at the output of the command using the 'var\_export' format. This will show the result of the command using the exact structure that was built by the command, without any reformatting. This is the standard format for the Drush command. Different formatters will take this information and present it in different ways. - -Global Options --------------- - -- --list-separator: Specify how elements in a list should be separated. In lists of lists, this applies to the elements in the inner lists. -- --line-separator: In nested lists of lists, specify how the outer lists ("lines") should be separated. - -Output Formats --------------- - -A list of available formats, and their affect on the output of certain Drush commands, is shown below. - diff --git a/docs/usage.md b/docs/usage.md index 8da73a6d44..d5c5df663b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -20,7 +20,7 @@ For multisite installations, use the --uri option to target a particular site. you are outside the Drupal web root, you will need to use the --root, --uri or other command line options just for Drush to work. - $ drush --uri=http://example.com pm-updatecode + $ drush --uri=http://example.com pm-enable If you wish to be able to select your Drupal site implicitly from the current working directory without using the --uri option, but you need your diff --git a/drush.api.php b/drush.api.php index 965aa9746e..7633bac46e 100644 --- a/drush.api.php +++ b/drush.api.php @@ -16,53 +16,6 @@ function hook_drush_sitealias_alter(&$alias_record) { } } -/** - * Take action after a project has been downloaded. - */ -function hook_drush_pm_post_download($project, $release) { - -} - -/** - * Adjust the location a project should be copied to after being downloaded. - * - * See @pm_drush_pm_download_destination_alter(). - */ -function hook_drush_pm_download_destination_alter(&$project, $release) { - if ($some_condition) { - $project['project_install_location'] = '/path/to/install/to/' . $project['project_dir']; - } -} - -/** - * Automatically download project dependencies at pm-enable time. - * - * Use a pre-pm_enable hook to download before your module is enabled, - * or a post-pm_enable hook (drush_hook_post_pm_enable) to run after - * your module is enabled. - * - * Your hook will be called every time pm-enable is executed; you should - * only download dependencies when your module is being enabled. Respect - * the --skip flag, and take no action if it is present. - */ -function drush_hook_pre_pm_enable() { - // Get the list of modules being enabled; only download dependencies if our - // module name appears in the list. - $modules = drush_get_context('PM_ENABLE_MODULES'); - if (in_array('hook', $modules) && !drush_get_option('skip')) { - $url = 'http://server.com/path/MyLibraryName.tgz'; - $path = drush_get_context('DRUSH_DRUPAL_ROOT'); - drush_include_engine('drupal', 'environment'); - if (drush_module_exists('libraries')) { - $path .= '/' . libraries_get_path('MyLibraryName') . '/MyLibraryName.tgz'; - } - else { - $path .= '/' . drupal_get_path('module', 'hook') . '/MyLibraryName.tgz'; - } - drush_download_file($url, $path) && drush_tarball_extract($path); - } -} - /** * Sql-sanitize example. * diff --git a/examples/example.bashrc b/examples/example.bashrc index 8062f99bbd..42e2ed16a5 100644 --- a/examples/example.bashrc +++ b/examples/example.bashrc @@ -22,12 +22,8 @@ # cca - drush cache-clear all # dis - drush pm-disable # en - drush pm-enable -# i - drush pm-info # pml - drush pm-list -# rf - drush pm-refresh # unin - drush pm-uninstall -# up - drush pm-update -# upc - drush pm-updatecode # updb - drush updatedb # q - drush sql-query # @@ -65,7 +61,6 @@ # Aliases for common Drush commands that work in a global context. alias dr='drush' alias ddd='drush drupal-directory' -alias dl='drush pm-download' alias ev='drush php-eval' alias sa='drush site-alias' alias lsa='drush site-alias --local-only' @@ -75,15 +70,9 @@ alias use='drush site-set' # Aliases for Drush commands that work on the current drupal site alias cc='drush cache-clear' alias cr='drush cache-rebuild' -alias cca='drush cache-clear all' -alias dis='drush pm-disable' alias en='drush pm-enable' -alias pmi='drush pm-info' alias pml='drush pm-list' -alias rf='drush pm-refresh' alias unin='drush pm-uninstall' -alias up='drush pm-update' -alias upc='drush pm-updatecode' alias updb='drush updatedb' alias q='drush sql-query' diff --git a/examples/example.drushrc.php b/examples/example.drushrc.php index acd8213799..5aabf1aa72 100644 --- a/examples/example.drushrc.php +++ b/examples/example.drushrc.php @@ -79,10 +79,8 @@ # $options['shell-aliases']['cpull'] = 'config-pull @example.prod @self --label=vcs'; # $options['shell-aliases']['noncore'] = 'pm-list --no-core'; # $options['shell-aliases']['wipe'] = 'cache-clear all'; -# $options['shell-aliases']['unsuck'] = 'pm-disable -y overlay,dashboard'; # $options['shell-aliases']['offline'] = 'state-set system.maintenance_mode 1 --input-format=integer'; # $options['shell-aliases']['online'] = 'state-set system.maintenance_mode 0 --input-format=integer'; -# $options['shell-aliases']['dis-all'] = '!drush -y dis `drush pml --status=enabled --type=module --no-core --pipe`'; # $options['shell-aliases']['self-alias'] = 'site-alias @self --with-db --alias-name=new'; # $options['shell-aliases']['site-get'] = '@none php-eval "return drush_sitealias_site_get();"'; // Save a sanitized sql dump. Customize alias names and --result-file. @@ -122,8 +120,8 @@ * substitution tokens are available: @DATABASE is replaced with the name of the * database being dumped, and @DATE is replaced with the current time and date * of the dump of the form: YYYYMMDD_HHMMSS. A value of TRUE ("--result-file=1" - * on the command line) will cause 'sql-dump' to use the same temporary backup - * location as 'pm-updatecode'. + * on the command line) will cause 'sql-dump' to generate a timestamped destination + * directory. */ # $options['result-file'] = TRUE; # $options['result-file'] = '/path/to/backup/dir/@DATABASE_@DATE.sql'; @@ -247,10 +245,6 @@ // Separate by : (Unix-based systems) or ; (Windows). # $command_specific['script']['script-path'] = 'sites/all/scripts:profiles/myprofile/scripts'; -// Always show release notes when running pm-update or pm-updatecode. -# $command_specific['pm-update'] = array('notes' => TRUE); -# $command_specific['pm-updatecode'] = array('notes' => TRUE); - // Set a predetermined username and password when using site-install. # $command_specific['site-install'] = array('account-name' => 'alice', 'account-pass' => 'secret'); diff --git a/includes/environment.inc b/includes/environment.inc index 549c372c64..919d122b98 100644 --- a/includes/environment.inc +++ b/includes/environment.inc @@ -664,155 +664,29 @@ function drush_directory_cache($subdir = '') { array('@locations' => implode(',', array_keys($cache_locations))))); } -/** - * Get complete information for all available extensions (modules and themes). - * - * @return - * An array containing info for all available extensions. In D8, these are Extension objects. - */ -function drush_get_extensions($include_hidden = TRUE) { - drush_include_engine('drupal', 'environment'); - $extensions = array_merge(drush_get_modules($include_hidden), drush_get_themes($include_hidden)); - foreach ($extensions as $name => $extension) { - if (isset($extension->info['name'])) { - $extensions[$name]->label = $extension->info['name'].' ('.$name.')'; - } - else { - drush_log(dt("Extension !name provides no human-readable name in .info file.", array('!name' => $name), LogLevel::DEBUG)); - $extensions[$name]->label = $name.' ('.$name.')'; - } - if (empty($extension->info['package'])) { - $extensions[$name]->info['package'] = dt('Other'); - } - } - return $extensions; -} - -/** - * Gets the extension name. - * - * @param $info - * The extension info. - * @return string - * The extension name. - */ -function drush_extension_get_name($info) { - drush_include_engine('drupal', 'environment'); - return _drush_extension_get_name($info); -} - -/** - * Gets the extension type. - * - * @param $info - * The extension info. - * @return string - * The extension type. - */ -function drush_extension_get_type($info) { - drush_include_engine('drupal', 'environment'); - return _drush_extension_get_type($info); -} - -/** - * Gets the extension path. - * - * @param $info - * The extension info. - * @return string - * The extension path. - */ -function drush_extension_get_path($info) { - drush_include_engine('drupal', 'environment'); - return _drush_extension_get_path($info); -} - -/** - * Test compatibility of a extension with version of drupal core and php. - * - * @param $file Extension object as returned by system_rebuild_module_data(). - * @return FALSE if the extension is compatible. - */ -function drush_extension_check_incompatibility($file) { - if (!isset($file->info['core']) || $file->info['core'] != drush_get_drupal_core_compatibility()) { - return 'Drupal'; - } - if (version_compare(phpversion(), $file->info['php']) < 0) { - return 'PHP'; - } - return FALSE; -} - -/** - * - */ -function drush_drupal_required_modules($modules) { - drush_include_engine('drupal', 'environment'); - return _drush_drupal_required_modules($modules); -} - -/** - * Return the default theme. - * - * @return - * Machine name of the default theme. - */ -function drush_theme_get_default() { - drush_include_engine('drupal', 'environment'); - return _drush_theme_default(); -} - -/** - * Return the administration theme. - * - * @return - * Machine name of the administration theme. - */ -function drush_theme_get_admin() { - drush_include_engine('drupal', 'environment'); - return _drush_theme_admin(); -} - -/** - * Return the path to public files directory. - */ -function drush_file_get_public() { - drush_include_engine('drupal', 'environment'); - return _drush_file_public_path(); -} - -/** - * Return the path to private files directory. - */ -function drush_file_get_private() { - drush_include_engine('drupal', 'environment'); - return _drush_file_private_path(); -} - -/** - * Returns the sitewide Drupal directory for extensions. - */ -function drush_drupal_sitewide_directory($major_version = NULL) { - if (!$major_version) { - $major_version = drush_drupal_major_version(); - } - return ($major_version < 8) ? 'sites/all' : ''; -} - -/** - * Helper function to get core compatibility constant. - * - * @return string - * The Drupal core compatibility constant. - */ -function drush_get_drupal_core_compatibility() { - if (defined('DRUPAL_CORE_COMPATIBILITY')) { - return DRUPAL_CORE_COMPATIBILITY; - } - elseif (defined('\Drupal::CORE_COMPATIBILITY')) { - return \Drupal::CORE_COMPATIBILITY; - } -} +///** +// * Get complete information for all available extensions (modules and themes). +// * +// * @return +// * An array containing info for all available extensions. In D8, these are Extension objects. +// */ +//function drush_get_extensions($include_hidden = TRUE) { +// drush_include_engine('drupal', 'environment'); +// $extensions = array_merge(drush_get_modules($include_hidden), drush_get_themes($include_hidden)); +// foreach ($extensions as $name => $extension) { +// if (isset($extension->info['name'])) { +// $extensions[$name]->label = $extension->info['name'].' ('.$name.')'; +// } +// else { +// drush_log(dt("Extension !name provides no human-readable name in .info file.", array('!name' => $name), LogLevel::DEBUG)); +// $extensions[$name]->label = $name.' ('.$name.')'; +// } +// if (empty($extension->info['package'])) { +// $extensions[$name]->info['package'] = dt('Other'); +// } +// } +// return $extensions; +//} /** * Set Env. Variables for given site-alias. diff --git a/src/Boot/DrupalBoot.php b/src/Boot/DrupalBoot.php index 1affba4dd8..ede4910540 100644 --- a/src/Boot/DrupalBoot.php +++ b/src/Boot/DrupalBoot.php @@ -173,7 +173,7 @@ function commandfile_searchpaths($phase, $phase_max = FALSE) { } // Check all enabled themes including non-default and non-admin. - foreach (drush_theme_list() as $key => $value) { + foreach (\Drupal::service('theme_handler')->listInfo() as $key => $value) { $searchpath[] = drupal_get_path('theme', $key); } // Drupal 8 uses the modules' services files to find commandfiles. Should we allow diff --git a/src/Commands/LegacyCommands.php b/src/Commands/LegacyCommands.php index d57661d13e..1a06b5a845 100644 --- a/src/Commands/LegacyCommands.php +++ b/src/Commands/LegacyCommands.php @@ -82,4 +82,13 @@ public function make() { $msg = 'Make has been removed, in favor of Composer. Use the make-convert command in Drush 8 to quickly upgrade your build to Composer.'; $this->logger()->notice($msg); } + + /** + * @command pm-download + * @aliases dl + */ + public function download() { + $msg = 'dl has been deprecated. Please build your site using Composer. Add new projects with composer require drupal/[project-name]. Use https://www.drupal.org/project/composer_generate to build a composer.json which represents the the enabled modules on your site.'; + $this->logger()->notice($msg); + } } diff --git a/src/Commands/core/CoreCommands.php b/src/Commands/core/CoreCommands.php index 7b14e78141..5824611e9d 100644 --- a/src/Commands/core/CoreCommands.php +++ b/src/Commands/core/CoreCommands.php @@ -50,7 +50,7 @@ public function twigCompile() { $searchpaths[] = drupal_get_path('module', $module); } - $themes = drush_theme_list(); + $themes = \Drupal::service('theme_handler')->listInfo(); foreach ($themes as $name => $theme) { $searchpaths[] = $theme->getPath(); } @@ -103,7 +103,7 @@ public function requirements($options = ['format' => 'table', 'severity' => -1, drupal_load_updates(); drush_include_engine('drupal', 'environment'); - $requirements = drush_module_invoke_all('requirements', 'runtime'); + $requirements = \Drupal::moduleHandler()->invokeAll('requirements', ['runtime']); // If a module uses "$requirements[] = " instead of // "$requirements['label'] = ", then build a label from // the title. diff --git a/src/Commands/core/StatusCommands.php b/src/Commands/core/StatusCommands.php index a1039de63d..0f5e1cf8db 100644 --- a/src/Commands/core/StatusCommands.php +++ b/src/Commands/core/StatusCommands.php @@ -2,13 +2,11 @@ namespace Drush\Commands\core; -use Consolidation\AnnotatedCommand\AnnotationData; use Consolidation\OutputFormatters\StructuredData\PropertyList; +use Drupal\Core\StreamWrapper\PrivateStream; +use Drupal\Core\StreamWrapper\PublicStream; use Drush\Commands\DrushCommands; use Drush\Sql\SqlBase; -use Symfony\Component\Console\Input\InputInterface; - -use Consolidation\OutputFormatters\StructuredData\AssociativeList; use Consolidation\OutputFormatters\Options\FormatterOptions; use Consolidation\AnnotatedCommand\CommandData; @@ -115,8 +113,8 @@ public static function getPropertyList($options) { } } if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { - $status_table['theme'] = drush_theme_get_default(); - $status_table['admin-theme'] = drush_theme_get_admin(); + $status_table['theme'] = \Drupal::config('system.theme')->get('default'); + $status_table['admin-theme'] = $theme = \Drupal::config('system.theme')->get('admin') ?: 'seven'; } } if ($php_bin = $options['php']) { @@ -173,7 +171,7 @@ public function adjustStatusOptions(CommandData $commandData) { public static function pathAliases($options) { $paths = array(); - $site_wide = drush_drupal_sitewide_directory(); + $site_wide = 'sites/all'; $boot = \Drush::bootstrap(); if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) { $paths['%root'] = $drupal_root; @@ -205,28 +203,17 @@ public static function pathAliases($options) { } if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { - $paths['%files'] = drush_file_get_public(); + $paths['%files'] = PublicStream::basePath(); $paths['%temp'] = file_directory_temp(); - if ($private_path = drush_file_get_private()) { + if ($private_path = PrivateStream::basePath()) { $paths['%private'] = $private_path; } } - - // If the 'project' parameter was specified, then search - // for a project (or a few) and add its path to the path list - if (!empty($options['project'])) { - drush_include_engine('drupal', 'environment'); - $projects = array_merge(drush_get_modules(), drush_get_themes()); - foreach(explode(',', $options['project']) as $target) { - if (array_key_exists($target, $projects)) { - $paths['%' . $target] = $drupal_root . '/' . _drush_extension_get_path($projects[$target]); - } - } - } } } // Add in all of the global paths from $options['path-aliases'] + // @todo is this used? if (isset($options['path-aliases'])) { $paths = array_merge($paths, $options['path-aliases']); } diff --git a/tests/UnishTestCase.php b/tests/UnishTestCase.php index 9a4ae82a42..ecc1e5a2db 100644 --- a/tests/UnishTestCase.php +++ b/tests/UnishTestCase.php @@ -510,12 +510,9 @@ function unish_file_aliases($aliases) { } /** - * @see drush_drupal_sitewide_directory() + * The sidewide directory for a Drupal 8 installation. */ function drupalSitewideDirectory($major_version = NULL) { - if (!$major_version) { - $major_version = UNISH_DRUPAL_MAJOR_VERSION; - } - return ($major_version < 8) ? '/sites/all' : ''; + return '/sites/all'; } } diff --git a/tests/releaseInfoTest.php b/tests/releaseInfoTest.php deleted file mode 100644 index ff534c4a90..0000000000 --- a/tests/releaseInfoTest.php +++ /dev/null @@ -1,61 +0,0 @@ -getSpecificRelease('6.x-1.18'); - $this->assertEquals('6.x-1.18', $release['version']); - - // Pick latest recommended+published with no further specification. - // 6.x-2.2 is skipped because it is unpublished. - // 6.x-2.2-rc1 is skipped because it is not a stable release. - $release = $project_release_info->getRecommendedOrSupportedRelease(); - $this->assertEquals('6.x-2.1', $release['version']); - - // Pick latest from a specific branch. - $release = $project_release_info->getSpecificRelease('6.x-1'); - $this->assertEquals('6.x-1.23', $release['version']); - - // Pick latest from a different branch. - // 6.x-2.2 is skipped because it is unpublished. - // 6.x-2.2-rc1 is skipped because it is not a stable release. - $release = $project_release_info->getSpecificRelease('6.x-2'); - $this->assertEquals('6.x-2.1', $release['version']); - - // Pick a -dev release. - $release = $project_release_info->getSpecificRelease('6.x-1.x'); - $this->assertEquals('6.x-1.x-dev', $release['version']); - - // Test UpdateServiceProject::getSpecificRelease(). - // Test we get latest release in branch 1. - $release = $project_release_info->getSpecificRelease('6.x-1'); - $this->assertEquals('6.x-1.23', $release['version']); - - // Test UpdateServiceProject::getDevRelease(). - $release = $project_release_info->getDevRelease(); - $this->assertEquals('6.x-1.x-dev', $release['version']); - } -}