diff --git a/libraries.api.php b/libraries.api.php index ac09743..029881d 100644 --- a/libraries.api.php +++ b/libraries.api.php @@ -15,7 +15,39 @@ * an associative array containing: * - name: The official, human-readable name of the library. * - vendor url: The URL of the homepage of the library. - * - download url: The URL of a web page on which the library can be obtained. + * - download url: (optional) The URL of a web page on which the library can + * be obtained. + * - download: (optional) An array of information for automated downloading of + * the library using Drush Make. The 'type' key specifies how the files + * be downloaded and also implies type-specific additional parameters. A + * subset of all available types and their options are described below, see + * http://drupalcode.org/project/drush_make.git/blob/refs/heads/6.x-3.x:/README.txt#l223 + * for more information: + * - file: Download a library as a single file. Additional keys are: + * - url: The URL of the file. In order for users to be able to download + * the library without knowing the latest version, the URL specified + * here should not contain the library's version, e.g. + * http://example.com/download/latest.tar.gz, if such a URL exists. + * Otherwise users will have to look up the latest version of the + * library before downloading it. + * - filename: (optional) What to name the file if it is not an archive. + * - git: Download the library from a Git repository. Additional keys are: + * - url: The URL of the repository. + * - tag: The tag to checkout. + * In the 'url', 'filename' and 'tag' values you can use the !version and + * !variant placeholders for specifying version- or variant-dependant + * information. These placeholders will be replaced dynamically. For example + * you can specify: + * @code + * $libraries['download']['url'] = 'http://example.com/download/!version-!variant.tar.gz'; + * @endcode + * And then running 'drush libraries-make example 1.2.3 --variant="min"' + * will request the URL: http://example.com/download/1.2.3-min.tar.gz. + * Also Git tags often correspond directly to version numbers, so you can + * specify: + * @code + * $libraries['download']['tag'] = '!version'; + * @endcode * - path: (optional) A relative path from the directory of the library to the * actual library. Only required if the extracted download package contains * the actual library files in a sub-directory. @@ -169,6 +201,16 @@ * - post-load: Callbacks registered in this group are applied directly * after this library is loaded. At this point, the library contains a * 'loaded' key, which contains the number of files that were loaded. + * - make: Callbacks registered in this group are applied before a library + * is downloaded via Drush Make. The 'downloads' property is passed to + * Drush Make, so it can be modified as needed. In this group the + * following properties are available: + * - $library['download_version']: The version that has been requested for + * download. + * - $library['download_variant']: The variant that has been requested for + * download. + * Both values can be an empty string, either if they are not required for + * this library, or if the user failed to supply them. * Additional top-level properties can be registered as needed. * * @see hook_library() @@ -183,7 +225,17 @@ function hook_libraries_info() { // Only used in administrative UI of Libraries API. 'name' => 'Example library', 'vendor url' => 'http://example.com', + // Optional: A website link to the library's download page. 'download url' => 'http://example.com/download', + // Optional: Information for automated downloading of the library. + 'download' => array( + // The type of download. + 'type' => 'file', + // The URL to download the library. The actual URL is e.g. + // http://example.com/download/example-1.2.3-minified.tar.gz, but the + // !version and !variant parts are replaced dynamically when downloading. + 'url' => 'http://example.com/download/example-!version-!variant.tar.gz', + ), // Optional: If, after extraction, the actual library files are contained in // 'sites/all/libraries/example/lib', specify the relative path here. 'path' => 'lib', @@ -312,6 +364,10 @@ function hook_libraries_info() { 'name' => 'Simple library', 'vendor url' => 'http://example.com/simple', 'download url' => 'http://example.com/simple', + 'download' => array( + 'type' => 'file', + 'url' => 'http://example.com/simple/latest/simple.tar.gz', + ), 'version arguments' => array( 'file' => 'readme.txt', // Best practice: Document the actual version strings for later reference. @@ -329,6 +385,11 @@ function hook_libraries_info() { 'name' => 'TinyMCE', 'vendor url' => 'http://tinymce.moxiecode.com', 'download url' => 'http://tinymce.moxiecode.com/download.php', + 'download' => array( + 'type' => 'git', + 'url' => 'http://github.com/tinymce/tinymce.git', + 'tag' => '!version', + ), 'path' => 'jscripts/tiny_mce', // The regular expression catches two parts (the major and the minor // version), which libraries_get_version() doesn't allow. diff --git a/libraries.drush.inc b/libraries.drush.inc index 26b35eb..57ebe08 100644 --- a/libraries.drush.inc +++ b/libraries.drush.inc @@ -9,18 +9,34 @@ * Implements hook_drush_command(). */ function libraries_drush_command() { + // List all registered libraries. $items['libraries-list'] = array( 'callback' => 'libraries_drush_list', - 'description' => dt('Lists registered library information.'), + 'description' => 'Lists registered library information.', 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL, ); - /**$items['libraries-download'] = array( - 'callback' => 'libraries_drush_download', - 'description' => dt('Downloads a registered library into the libraries directory for the active site.'), - 'arguments' => array( - 'name' => dt('The internal name of the registered library.'), - ), - );*/ + + // Make sure Drush Make is available (4.x or 5.x) to allow automated + // downloading of libraries. + if (function_exists('drush_make_download_factory') || function_exists('make_download_factory')) { + $items['libraries-make'] = array( + 'callback' => 'libraries_drush_make', + 'description' => 'Downloads a registered library into the libraries directory for the active site.', + 'arguments' => array( + 'name' => 'The internal name of the registered library.', + 'version' => '(optional) The version of the library to download. For libraries that have a static download URL, this does not need to specified.', + ), + 'options' => array( + 'variant' => 'The variant of the library to download.', + 'destination' => 'Destination path (from Drupal root) for the library to be installed to. Defaults to "sites/all/libraries"', + ), + 'examples' => array( + 'drush libraries-make tinymce 3.4.7' => 'Downloads version 3.4.7 of the TinyMCE library.', + 'drush libraries-make tinymce --destination="sites/example.com/libraries"' => 'Downloads TinyMCE to the "libraries" directory for example.com.', + 'drush libraries-make jquery 1.7.1 --variant="min"' => 'Downloads the minified variant of the 1.7.1 version of jQuery.', + ), + ); + } return $items; } @@ -32,10 +48,8 @@ function libraries_drush_help($section) { case 'drush:libraries-list': return dt('Lists registered library information.'); - case 'drush:libraries-download': - return dt('Downloads a registered library into the libraries directory for the active site. - -See libraries-list for a list of registered libraries.'); + case 'drush:libraries-make': + return dt('Downloads a registered library into the libraries directory.'); } } @@ -50,7 +64,7 @@ function libraries_drush_list() { ksort($libraries); if (empty($libraries)) { - drush_print('There are no registered libraries.'); + return drush_log(dt('There are no registered libraries.'), 'success'); } else { @@ -88,64 +102,125 @@ function libraries_drush_list() { * @param $name * The internal name of the library to download. */ -function libraries_drush_download($name) { - return; +function libraries_drush_make($name = '', $version = '') { + $variant = drush_get_option('variant', ''); - // @todo Looks wonky? - if (!drush_shell_exec('type unzip')) { - return drush_set_error(dt('Missing dependency: unzip. Install it before using this command.')); + // Make sure a library is provided. + if (empty($name)) { + return drush_log(dt('Please specify which library to download. See "drush libraries-list" for a list of available libraries.'), 'warning'); } - // @todo Simply use current drush site. - $args = func_get_args(); - if ($args[0]) { - $path = $args[0]; - } - else { - $path = 'sites/all/libraries'; + // Check if the library is defined. + $library = libraries_info($name); + if (empty($library)) { + return drush_log(dt('The given library, "@name", was not found.', array('@name' => $name)), 'error'); } - // Create the path if it does not exist. - if (!is_dir($path)) { - drush_op('mkdir', $path); - drush_log(dt('Directory @path was created', array('@path' => $path)), 'notice'); + // The download options may differ depending on the requested version or + // variant. + if (!empty($version) && isset($library['versions'][$version])) { + $library = array_merge($library, $library['versions'][$version]); + } + if (!empty($variant) && isset($library['variants'][$variant])) { + $library = array_merge($library, $library['variants'][$variant]); } - // Set the directory to the download location. - $olddir = getcwd(); - chdir($path); + // Check if automated downloading of this library is available. + if (!isset($library['download'])) { + return drush_log(dt('Automated downloading of @name is not supported.', array('@name' => $name)), 'error'); + } - $filename = basename(COLORBOX_DOWNLOAD_URI); - $dirname = basename(COLORBOX_DOWNLOAD_URI, '.zip'); + // Invoke callbacks in the 'make' group. + // Callbacks in the 'make' group can react to the specified version and + // variant. + $library['version_to_download'] = $version; + $library['variant_to_download'] = $variant; + libraries_invoke('make', $library); - // Remove any existing Colorbox plugin directory - if (is_dir($dirname)) { - drush_log(dt('A existing Colorbox plugin was overwritten at @path', array('@path' => $path)), 'notice'); - } - // Remove any existing Colorbox plugin zip archive - if (is_file($filename)) { - drush_op('unlink', $filename); + // Callbacks in the 'make' group can set errors, as well. + if (!empty($library['error'])) { + return drush_log($library['error message'], 'error'); } - // Download the zip archive - if (!drush_shell_exec('wget '. COLORBOX_DOWNLOAD_URI)) { - drush_shell_exec('curl -O '. COLORBOX_DOWNLOAD_URI); + // Allow manual overriding of any given download options. + $options = array('type', 'url', 'filename', 'tag'); + foreach ($options as $index => $option) { + $value = drush_get_option($option, ''); + if (!empty($value)) { + $library['download'][$option] = $value; + } } - if (is_file($filename)) { - // Decompress the zip archive - drush_shell_exec('unzip -qq -o '. $filename); - // Remove the zip archive - drush_op('unlink', $filename); - } + // Figure out where we want to save the library. + $destination = drush_get_option('destination', 'sites/all/libraries'); + $destination = DRUPAL_ROOT . '/' . $destination . '/' . $name; + + // Create the directory. + drush_mkdir($destination); - // Set working directory back to the previous working directory. - chdir($olddir); + // Support for both Drush Make 4.x and 5.x. + $make = function_exists('drush_make_download_factory') ? 'drush_make_download_factory' : 'make_download_factory'; + $make($name, $library['download'], $destination); - if (is_dir($path .'/'. $dirname)) { - drush_log(dt('Colorbox plugin has been downloaded to @path', array('@path' => $path)), 'success'); + // Check that the directory is not empty. + $files = array_diff(scandir($destination), array('.', '..')); + if (!empty($files)) { + return drush_log(dt('The @name library was downloaded to @path.', array( + '@name' => $name, + '@path' => $destination, + )), 'success'); } else { - drush_log(dt('Drush was unable to download the Colorbox plugin to @path', array('@path' => $path)), 'error'); + return drush_log(dt('There was an error downloading @name to @destination.', array( + '@name' => $name, + '@destination' => $destination, + )), 'error'); + } +} + +/** + * Prepares the download information of libraries for Drush Make. + * + * This replaces !version and !variant placeholders in the download URL or in + * Git tags with the respective parameters. + * + * @param $library + * An associative array of library information or a part of it, passed by + * reference. + * @param $version + * If the library information belongs to a specific version, the version + * string. NULL otherwise. + * @param $variant + * If the library information belongs to a specific variant, the variant name. + * NULL otherwise. + * + * @see libraries_info() + * @see libraries_invoke() + */ +function libraries_prepare_make_download(&$library, $version = NULL, $variant = NULL) { + if (!empty($library['download'])) { + // We support the !version and !variant placeholders for all of these values. + foreach (array('url', 'filename', 'tag') as $key) { + if (isset($library['download'][$key])) { + $value = $library['download'][$key]; + // If one of the placeholders was used in the value, but was not specified, + // set an error. + if (strpos($value, '!version') && empty($library['version_to_download'])) { + $library['error'] = 'version not specified'; + $library['error message'] = dt('The version to download was not specified.'); + return; + } + elseif (strpos($value, '!variant') && empty($library['variant_to_download'])) { + $library['error'] = 'variant not specified'; + $library['error message'] = dt('The variant to download was not specified.'); + return; + } + + $library['download'][$key] = format_string($library['download'][$key], array( + '!version' => $library['version_to_download'], + '!variant' => $library['variant_to_download'], + )); + } + } } } diff --git a/libraries.info b/libraries.info index 208a14e..a3555c8 100644 --- a/libraries.info +++ b/libraries.info @@ -1,4 +1,6 @@ name = Libraries description = Allows version dependent and shared usage of external libraries. core = 7.x +; We use format_string() +dependencies[] = system (>=7.10) files[] = tests/libraries.test diff --git a/libraries.module b/libraries.module index c67ce79..1e48177 100644 --- a/libraries.module +++ b/libraries.module @@ -407,11 +407,13 @@ function libraries_info_defaults(&$library, $name) { 'post-detect' => array(), 'pre-load' => array(), 'post-load' => array(), + 'make' => array(), ); // Add our own callbacks before any others. array_unshift($library['callbacks']['info'], 'libraries_prepare_files'); array_unshift($library['callbacks']['post-detect'], 'libraries_detect_dependencies'); + array_unshift($library['callbacks']['make'], 'libraries_prepare_make_download'); return $library; }