? 542940-libraries_drush-21.patch ? 864376-libraries-external-20.patch ? 864376-libraries-external-26.patch ? libraries-static.patch Index: libraries.api.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.api.php,v retrieving revision 1.4 diff -u -p -r1.4 libraries.api.php --- libraries.api.php 9 Oct 2010 22:26:03 -0000 1.4 +++ libraries.api.php 10 Oct 2010 04:40:41 -0000 @@ -17,9 +17,21 @@ * - title: 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. + * - library path: (optional) The absolute path to the library directory. This + * should not be declared normally, as it is automatically detected, to + * allow for multiple possible library locations. A valid use-case is an + * external library, in which case the full URL to the library should be + * specified here. * - 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. + * - version: (optional) The version of the library. This should not be + * declared normally, as it is automatically detected (see 'version + * callback' below) to allow for version changes of libraries without code + * changes of implementing modules and to support different versions of a + * library simultaneously (though only one version can be installed per + * site). A valid use-case is an external library whose version cannot be + * determined programatically. * - version callback: (optional) The name of a function that detects and * returns the full version string of the library. The first argument is * always $library, an array containing all library information as described @@ -311,6 +323,34 @@ function hook_libraries_info() { ), ), ); + // An example library that is external. It has a local and a remote variant. + $libraries['openlayers'] = array( + 'title' => 'OpenLayers', + 'vendor url' => 'http://www.openlayers.org/', + 'download url' => 'http://trac.osgeo.org/openlayers/wiki/HowToDownload', + // This makes Libraries API not scan the filesystem for the library. + 'library path' => 'http://openlayers.org/api/OpenLayers.js', + // This should determine which variant is available, the local or the remote + // one, (with libraries_get_path()) and then conditionally determine the + // version (with libraries_get_version() and the respective parameters). + 'version callback' => 'openlayers_get_version', + // The explicit declaration below is in part redundant, but is used here for + // demonstration purposes. + 'variants' => array( + 'local' => array( + 'library path' => libraries_get_path('openlayers'), + 'files' => array( + 'js' => array('OpenLayers.js'), + ), + ), + 'remote' => array( + 'library path' => 'http://openlayers.org/api', + 'files' => array( + 'js' => array('OpenLayers.js'), + ), + ), + ), + ); return $libraries; } Index: libraries.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.module,v retrieving revision 1.8 diff -u -p -r1.8 libraries.module --- libraries.module 10 Oct 2010 03:55:16 -0000 1.8 +++ libraries.module 10 Oct 2010 04:40:41 -0000 @@ -259,26 +259,28 @@ function libraries_detect_library(&$libr if (!isset($library['library path'])) { $library['library path'] = libraries_get_path($name); } - if (!file_exists($library['library path'])) { + if (!libraries_file_exists($library['library path'])) { $library['error'] = 'not found'; $library['error message'] = t('%library could not be found.', array('%library' => $library['title'])); return; } - // Detect library version. - // We support both a single parameter, which is an associative array, and an - // indexed array of multiple parameters. - if (isset($library['version arguments'][0])) { - // Add the library as the first argument. - $library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments'])); - } - else { - $library['version'] = $library['version callback']($library, $library['version arguments']); - } - if (empty($library['version'])) { - $library['error'] = 'not detected'; - $library['error message'] = t('The version of %library could not be detected.', array('%library' => $library['title'])); - return; + // Detect library version, if not hardcoded. + if (!isset($library['version'])) { + // We support both a single parameter, which is an associative array, and an + // indexed array of multiple parameters. + if (isset($library['version arguments'][0])) { + // Add the library as the first argument. + $library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments'])); + } + else { + $library['version'] = $library['version callback']($library, $library['version arguments']); + } + if (empty($library['version'])) { + $library['error'] = 'not detected'; + $library['error message'] = t('The version of %library could not be detected.', array('%library' => $library['title'])); + return; + } } // Determine to which supported version the installed version maps. @@ -346,7 +348,11 @@ function libraries_detect_library(&$libr function libraries_load($library, $variant = NULL) { $library = libraries_info($library); libraries_detect_library($library); - libraries_load_files($library, $variant); + if ($library['installed']) { + libraries_load_files($library, $variant); + return TRUE; + } + return FALSE; } /** @@ -359,11 +365,11 @@ function libraries_load($library, $varia */ function libraries_load_files($library, $variant = NULL) { // Construct the full path to the library for later use. - $path = !empty($library['path']) ? $library['library path'] . '/' . $library['path'] : $library['library path']; + $path = (!empty($library['path']) ? $library['library path'] . '/' . $library['path'] : $library['library path']); // If a variant was specified, override the top-level properties with the // variant properties. - if (!empty($variant) && !empty($library['variants'][$variant]['installed'])) { + if (!empty($variant) && $library['variants'][$variant]['installed']) { $library = array_merge($library, $library['variants'][$variant]); } @@ -387,12 +393,14 @@ function libraries_load_files($library, // If the value is not an array, it's a filename and passed as first // (and only) argument. if (!is_array($options)) { - // Prepend the library path to the file name. - $data = "$path/$options"; + // Prepend the library path to the file name, if it is not an external + // file. + $data = (url_is_external($options) ? $options : "$path/$options"); $options = NULL; } - // In some cases, the first parameter ($data) is an array. Arrays can't be - // passed as keys in PHP, so we have to get $data from the value array. + // In some cases, the first parameter ($data) is an array. Arrays can't + // be passed as keys in PHP, so we have to get $data from the value + // array. if (is_numeric($data)) { $data = $options['data']; unset($options['data']); @@ -409,9 +417,9 @@ function libraries_load_files($library, // Load PHP files. if (!empty($library['files']['php'])) { foreach ($library['files']['php'] as $file) { - $file_path = DRUPAL_ROOT . '/' . $path . '/' . $file; - if (file_exists($file_path)) { - require_once $file_path; + $file = (url_is_external($file) ? $file : DRUPAL_ROOT . '/' . $path . '/' . $file); + if (libraries_file_exists($file)) { + include_once $file; } } } @@ -448,8 +456,8 @@ function libraries_get_version($library, 'cols' => 200, ); - $file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $options['file']; - if (empty($options['file']) || !file_exists($file)) { + $file = (url_is_external($options['file']) ? $options['file'] : DRUPAL_ROOT . '/' . $library['library path'] . '/' . $options['file']); + if (empty($options['file']) || !libraries_file_exists($file)) { return; } $file = fopen($file, 'r'); @@ -463,3 +471,19 @@ function libraries_get_version($library, fclose($file); } +/** + * Wrapper function for file_exists() with support for external files. + * + * For external files, it doesn't actually check their availability, as that + * would have to be done with fopen, which causes significant overhead. Instead, + * it simply assumes all external files to exist. + * + * @param $file + * The path to the file. In case of an external file the full URL. + * + * @return + * A boolean indicating whether this file exists or not. + */ +function libraries_file_exists($file) { + return url_is_external($file) || file_exists($file); +} Index: tests/libraries.test =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/tests/libraries.test,v retrieving revision 1.5 diff -u -p -r1.5 libraries.test --- tests/libraries.test 9 Oct 2010 22:26:03 -0000 1.5 +++ tests/libraries.test 10 Oct 2010 04:40:41 -0000 @@ -7,6 +7,7 @@ */ class LibrariesTestCase extends DrupalWebTestCase { + protected $profile = 'testing'; public static function getInfo() { return array( @@ -119,6 +120,16 @@ class LibrariesTestCase extends DrupalWe libraries_detect_library($library); $this->assertEqual($library['variants']['example_variant']['installed'], TRUE, 'Existing variant found.'); + // Test external library. + $library = libraries_info('example_external'); + libraries_detect_library($library); + $this->assertEqual($library['installed'], TRUE, 'External library found.'); + + // Test external library with version callback. + $library = libraries_info('example_external_version'); + libraries_detect_library($library); + $this->assertEqual($library['version'], '2', 'Library version of an external library found.'); + // Test loading of a simple library with a top-level files property. $this->drupalGet('libraries_test/simple'); $this->assertLibraryFiles('example_1'); @@ -140,6 +151,12 @@ class LibrariesTestCase extends DrupalWe // Test version overloading and variant loading. $this->drupalGet('libraries_test/versions_and_variants'); $this->assertLibraryFiles('example_4'); + + // Test loading of an external library. + // Because this needs 'allow_url_fopen' and 'allow_url_include' to pass, it + // is commented out, but can be used for testing purposes. + // $this->drupalGet('libraries_test/external'); + // $this->assertLibraryFiles('example_1'); } /** Index: tests/libraries_test.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/tests/libraries_test.module,v retrieving revision 1.5 diff -u -p -r1.5 libraries_test.module --- tests/libraries_test.module 10 Oct 2010 03:55:16 -0000 1.5 +++ tests/libraries_test.module 10 Oct 2010 04:40:41 -0000 @@ -12,19 +12,22 @@ function libraries_test_libraries_info() { // Test library detection. $libraries['example_missing'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/missing', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('1'), ); $libraries['example_undetected_version'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests', 'version callback' => '_libraries_test_return_version', 'version arguments' => array(FALSE), ); $libraries['example_unsupported_version'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('1'), @@ -32,9 +35,9 @@ function libraries_test_libraries_info() '2' => array(), ), ); - $libraries['example_supported_version'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('2'), @@ -43,9 +46,34 @@ function libraries_test_libraries_info() ), ); + // Test external libraries. + $external_path = url(NULL, array('absolute' => TRUE)) . drupal_get_path('module', 'libraries_test'); + $libraries['example_external'] = array( + // External libraries specify a file as library path, not a directory. + 'library path' => "$external_path/example/README.txt", + 'version' => '2', + 'files' => array( + 'js' => array("$external_path/example/example_1.js"), + 'css' => array("$external_path/example/example_1.css"), + 'php' => array("$external_path/example/example_1.php"), + ), + ); + $libraries['example_external_version'] = array( + // External libraries specify a file as library path, not a directory. + 'library path' => "$external_path/example/README.txt", + 'version callback' => 'libraries_get_version', + 'version arguments' => array( + 'file' => "$external_path/example/README.txt", + // Version 2 + 'pattern' => '/Version (\d+)/', + 'lines' => 5, + ), + ); + // Test the default version callback. $libraries['example_default_version_callback'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version arguments' => array( 'file' => 'README.txt', @@ -57,7 +85,8 @@ function libraries_test_libraries_info() // Test a multiple-parameter version callback. $libraries['example_multiple_parameter_version_callback'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', // Version 2 'version callback' => '_libraries_test_get_version', @@ -66,20 +95,15 @@ function libraries_test_libraries_info() // Test a top-level files property. $libraries['example_simple'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('1'), 'files' => array( - 'js' => array( - 'example_1.js', - ), - 'css' => array( - 'example_1.css', - ), - 'php' => array( - 'example_1.php' - ), + 'js' => array('example_1.js'), + 'css' => array('example_1.css'), + 'php' => array('example_1.php'), ), ); @@ -87,56 +111,40 @@ function libraries_test_libraries_info() // Normally added by the corresponding module via hook_libraries_info_alter(), // these files should be automatically loaded when the library is loaded. $libraries['example_integration_files'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('2'), 'integration files' => array( 'libraries_test' => array( - 'js' => array( - 'libraries_test.js', - ), - 'css' => array( - 'libraries_test.css', - ), - 'php' => array( - 'libraries_test.inc', - ), + 'js' => array('libraries_test.js'), + 'css' => array('libraries_test.css'), + 'php' => array('libraries_test.inc'), ), ), ); // Test version overloading. $libraries['example_versions'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('2'), 'versions' => array( '1' => array( 'files' => array( - 'js' => array( - 'example_1.js', - ), - 'css' => array( - 'example_1.css', - ), - 'php' => array( - 'example_1.php', - ), + 'js' => array('example_1.js'), + 'css' => array('example_1.css'), + 'php' => array('example_1.php'), ), ), '2' => array( 'files' => array( - 'js' => array( - 'example_2.js', - ), - 'css' => array( - 'example_2.css', - ), - 'php' => array( - 'example_2.php', - ), + 'js' => array('example_2.js'), + 'css' => array('example_2.css'), + 'php' => array('example_2.php'), ), ), ), @@ -144,22 +152,17 @@ function libraries_test_libraries_info() // Test variant detection. $libraries['example_variant_missing'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('2'), 'variants' => array( 'example_variant' => array( 'files' => array( - 'js' => array( - 'example_3.js', - ), - 'css' => array( - 'example_3.css', - ), - 'php' => array( - 'example_3.php', - ), + 'js' => array('example_3.js'), + 'css' => array('example_3.css'), + 'php' => array('example_3.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(FALSE), @@ -168,22 +171,17 @@ function libraries_test_libraries_info() ); $libraries['example_variant'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('2'), 'variants' => array( 'example_variant' => array( 'files' => array( - 'js' => array( - 'example_3.js', - ), - 'css' => array( - 'example_3.css', - ), - 'php' => array( - 'example_3.php', - ), + 'js' => array('example_3.js'), + 'css' => array('example_3.css'), + 'php' => array('example_3.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), @@ -193,7 +191,8 @@ function libraries_test_libraries_info() // Test correct behaviour with multiple versions and multiple variants. $libraries['example_versions_and_variants'] = array( - // Never declare library path manually. It is detected automatically. + // Never declare the library path manually (except for external libraries). + // It is detected automatically. 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('2'), @@ -202,30 +201,18 @@ function libraries_test_libraries_info() 'variants' => array( 'example_variant_1' => array( 'files' => array( - 'js' => array( - 'example_1.js', - ), - 'css' => array( - 'example_1.css', - ), - 'php' => array( - 'example_1.php', - ), + 'js' => array('example_1.js'), + 'css' => array('example_1.css'), + 'php' => array('example_1.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), ), 'example_variant_2' => array( 'files' => array( - 'js' => array( - 'example_2.js', - ), - 'css' => array( - 'example_2.css', - ), - 'php' => array( - 'example_2.php', - ), + 'js' => array('example_2.js'), + 'css' => array('example_2.css'), + 'php' => array('example_2.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), @@ -236,30 +223,18 @@ function libraries_test_libraries_info() 'variants' => array( 'example_variant_1' => array( 'files' => array( - 'js' => array( - 'example_3.js', - ), - 'css' => array( - 'example_3.css', - ), - 'php' => array( - 'example_3.php', - ), + 'js' => array('example_3.js'), + 'css' => array('example_3.css'), + 'php' => array('example_3.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), ), 'example_variant_2' => array( 'files' => array( - 'js' => array( - 'example_4.js', - ), - 'css' => array( - 'example_4.css', - ), - 'php' => array( - 'example_4.php', - ), + 'js' => array('example_4.js'), + 'css' => array('example_4.css'), + 'php' => array('example_4.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), @@ -384,6 +359,14 @@ function libraries_test_menu() { 'page arguments' => array('example_versions_and_variants', 'example_variant_2'), 'access callback' => TRUE, ); + // Note that the corresponding test for this menu item is commented out, due + // to its dependence on 'allow_url_fopen' and 'allow_url_include'. + $items['libraries_test/external'] = array( + 'title' => 'Test loading of an external library', + 'page callback' => '_libraries_test_load', + 'page arguments' => array('example_external'), + 'access callback' => TRUE, + ); return $items; }