├── .gitignore ├── README.md ├── composer.json ├── composer.lock └── src └── Plugin.php /.gitignore: -------------------------------------------------------------------------------- 1 | # composer artifacts 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Drupal Libraries Installer 2 | 3 | _Drupal Libraries Installer_ is a [composer][composer] plugin that allows for easily 4 | managing external libraries required for Drupal modules/themes that are not available 5 | as composer packages. This plugin is another piece of the puzzle towards managing all 6 | external dependencies for a Drupal site in a single place: the `composer.json` file. 7 | 8 | ## How to Use 9 | 10 | 1. Add _Drupal Libraries Installer_ to your Drupal site project: 11 | 12 | ```sh 13 | composer require balbuf/drupal-libraries-installer 14 | ``` 15 | 16 | 1. Add libraries to your `composer.json` file via the `drupal-libraries` property 17 | within `extra`. A library is specified using its name as the key and a URL to its 18 | distribution ZIP file as the value: 19 | 20 | ```json 21 | { 22 | "extra": { 23 | "drupal-libraries": { 24 | "flexslider": "https://github.com/woocommerce/FlexSlider/archive/2.6.4.zip", 25 | "chosen": "https://github.com/harvesthq/chosen/releases/download/v1.8.2/chosen_v1.8.2.zip" 26 | } 27 | } 28 | } 29 | ``` 30 | _See below for how to find the ZIP URL for a GitHub repo._ 31 | 32 | 1. Ensure composer packages of type `drupal-library` are configured to install to the 33 | appropriate path. By default, [`composer/installers`][installers] (a dependency of 34 | this plugin and likely already included in your project) will install these packages 35 | to `/libraries/{$name}/` in the root of your repo. You may wish to change this via 36 | the `installer-paths` property (within `extra`) of your `composer.json`: 37 | 38 | ```json 39 | { 40 | "extra": { 41 | "installer-paths": { 42 | "web/libraries/{$name}/": ["type:drupal-library"] 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | _See the `composer/installers` [README][installers readme] for more information on 49 | the `installer-paths` property._ 50 | 51 | 1. Run `composer install`. Libraries are downloaded and unpacked into place upon running 52 | `composer install` or `composer update`. (To upgrade a library, simply swap out its URL 53 | in your `composer.json` file and run `composer install` again.) 54 | 55 | ## How to Reference a GitHub Repo as a ZIP File 56 | 57 | If you are directed to download a library from its GitHub repo, follow these instructions 58 | to find a link to the ZIP file version of the code base: 59 | 60 | ### Preferred Method 61 | 62 | It is best to reference a specific release of the library so that the same version of 63 | code is downloaded every time for each user of the project. To see what releases are 64 | available: 65 | 66 | 1. Click the `X releases` link (where `X` is some number) near the top of the 67 | GitHub repo's home page. You can also reach the release page by appending `/releases/` 68 | to the repo's home page URL, e.g. for `https://github.com/harvesthq/chosen`, you'd 69 | go to `https://github.com/harvesthq/chosen/releases/`. 70 | 71 | 1. Identify which release you'd like to use. You'll likely want to use the latest release 72 | unless the module noted a specific version requirement. 73 | 74 | 1. For that release, find the "Assets" section. If the repo provides its own distribution 75 | ZIP file, that will be listed as one of the first files in the list. If so, you'll want to 76 | try using that first in case it includes pre-built files not available directly in the repo. 77 | Otherwise, use the "Source code (zip)" link for that release. Simply copy the URL for the 78 | desired link to use within your `composer.json` file. 79 | 80 | ### Alternate Method 81 | 82 | If the library does not provide any releases, you can still reference it in ZIP file form. 83 | The downside is that any time you download this ZIP, the contents may change based on the 84 | state of the repo. There is no guarantee that separate users of the project will have the 85 | exact same version of the library. 86 | 87 | 1. Click the green `Clone or download` button on the repo's home page. 88 | 89 | 1. Copy the URL for the `Download ZIP` link to use within your `composer.json` file. 90 | 91 | ## Notes 92 | 93 | - Only ZIP files are supported at this time. 94 | - This plugin is meant to be used with a root package only (i.e. a Drupal site repo) 95 | and will not find libraries listed in the `composer.json` files of dependencies 96 | (e.g. contrib modules). 97 | - This plugin is essentially a shortcut for explicitly declaring the composer package 98 | information for each library zip you need to include in your project, e.g.: 99 | ```json 100 | { 101 | "repositories": [ 102 | { 103 | "type": "package", 104 | "package": { 105 | "name": "harvesthq/chosen", 106 | "version": "1.8.2", 107 | "type": "drupal-library", 108 | "dist": { 109 | "url": "https://github.com/harvesthq/chosen/releases/download/v1.8.2/chosen_v1.8.2.zip", 110 | "type": "zip" 111 | } 112 | } 113 | } 114 | ], 115 | "require": { 116 | "harvesthq/chosen": "1.8.2" 117 | } 118 | } 119 | ``` 120 | While that method is perfectly viable and works right out of the box with no additional 121 | plugin, it is also cumbersome, not very user-friendly, and quite verbose, adding 122 | a lot of additional noise to your `composer.json` file. 123 | - Libraries are installed after actual composer packages are installed and are not 124 | subject to the dependency-resolving algorithm inherent to composer. What this means 125 | is that libraries cannot be specified with a range of compatible versions (rather, 126 | a specific version of a library's distribution file must be chosen), and if libraries 127 | have any other additional library dependencies of their own, these must be explicitly 128 | added to the list. 129 | - Because libraries are installed after composer packages, it's possible that a library 130 | installed by this plugin could overwrite a composer package in the event of an 131 | install-path collision. 132 | - While many libraries are JS- and/or CSS-based and available via [npm][npm], there is 133 | no way to install these packages directly into the proper /libraries/ folder with npm. 134 | As well, modules will often list their external library requirements as links to ZIP 135 | distribution files or GitHub repos, making it easier to reference and pull in these 136 | dependencies in that manner with this plugin. 137 | - This plugin is intended only as a short-term solution for the broader issue of 138 | external library dependency management among modules and themes. 139 | 140 | [composer]: https://getcomposer.org/ 141 | [npm]: https://www.npmjs.com/ 142 | [installers]: https://packagist.org/packages/composer/installers 143 | [installers readme]: https://github.com/composer/installers#custom-install-paths 144 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "balbuf/drupal-libraries-installer", 3 | "description": "Install Drupal libraries via a simple listing in your composer.json file", 4 | "type": "composer-plugin", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Stephen Beemsterboer", 9 | "homepage": "https://github.com/balbuf" 10 | } 11 | ], 12 | "support": { 13 | "issues": "https://github.com/balbuf/drupal-libraries-installer/issues" 14 | }, 15 | "autoload": { 16 | "psr-4": {"BalBuf\\DrupalLibrariesInstaller\\": "src/"} 17 | }, 18 | "extra": { 19 | "class": "BalBuf\\DrupalLibrariesInstaller\\Plugin" 20 | }, 21 | "require": { 22 | "composer-plugin-api": "^1.0", 23 | "composer/installers": "^1.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "0d5407f7f7233a1bd639fd22d5542230", 8 | "packages": [ 9 | { 10 | "name": "composer/installers", 11 | "version": "v1.5.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/composer/installers.git", 15 | "reference": "049797d727261bf27f2690430d935067710049c2" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/composer/installers/zipball/049797d727261bf27f2690430d935067710049c2", 20 | "reference": "049797d727261bf27f2690430d935067710049c2", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "composer-plugin-api": "^1.0" 25 | }, 26 | "replace": { 27 | "roundcube/plugin-installer": "*", 28 | "shama/baton": "*" 29 | }, 30 | "require-dev": { 31 | "composer/composer": "1.0.*@dev", 32 | "phpunit/phpunit": "^4.8.36" 33 | }, 34 | "type": "composer-plugin", 35 | "extra": { 36 | "class": "Composer\\Installers\\Plugin", 37 | "branch-alias": { 38 | "dev-master": "1.0-dev" 39 | } 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "Composer\\Installers\\": "src/Composer/Installers" 44 | } 45 | }, 46 | "notification-url": "https://packagist.org/downloads/", 47 | "license": [ 48 | "MIT" 49 | ], 50 | "authors": [ 51 | { 52 | "name": "Kyle Robinson Young", 53 | "email": "kyle@dontkry.com", 54 | "homepage": "https://github.com/shama" 55 | } 56 | ], 57 | "description": "A multi-framework Composer library installer", 58 | "homepage": "https://composer.github.io/installers/", 59 | "keywords": [ 60 | "Craft", 61 | "Dolibarr", 62 | "Eliasis", 63 | "Hurad", 64 | "ImageCMS", 65 | "Kanboard", 66 | "Lan Management System", 67 | "MODX Evo", 68 | "Mautic", 69 | "Maya", 70 | "OXID", 71 | "Plentymarkets", 72 | "Porto", 73 | "RadPHP", 74 | "SMF", 75 | "Thelia", 76 | "WolfCMS", 77 | "agl", 78 | "aimeos", 79 | "annotatecms", 80 | "attogram", 81 | "bitrix", 82 | "cakephp", 83 | "chef", 84 | "cockpit", 85 | "codeigniter", 86 | "concrete5", 87 | "croogo", 88 | "dokuwiki", 89 | "drupal", 90 | "eZ Platform", 91 | "elgg", 92 | "expressionengine", 93 | "fuelphp", 94 | "grav", 95 | "installer", 96 | "itop", 97 | "joomla", 98 | "kohana", 99 | "laravel", 100 | "lavalite", 101 | "lithium", 102 | "magento", 103 | "majima", 104 | "mako", 105 | "mediawiki", 106 | "modulework", 107 | "modx", 108 | "moodle", 109 | "osclass", 110 | "phpbb", 111 | "piwik", 112 | "ppi", 113 | "puppet", 114 | "pxcms", 115 | "reindex", 116 | "roundcube", 117 | "shopware", 118 | "silverstripe", 119 | "sydes", 120 | "symfony", 121 | "typo3", 122 | "wordpress", 123 | "yawik", 124 | "zend", 125 | "zikula" 126 | ], 127 | "time": "2017-12-29T09:13:20+00:00" 128 | } 129 | ], 130 | "packages-dev": [], 131 | "aliases": [], 132 | "minimum-stability": "stable", 133 | "stability-flags": [], 134 | "prefer-stable": false, 135 | "prefer-lowest": false, 136 | "platform": [], 137 | "platform-dev": [] 138 | } 139 | -------------------------------------------------------------------------------- /src/Plugin.php: -------------------------------------------------------------------------------- 1 | 'install', 33 | ScriptEvents::POST_UPDATE_CMD => 'install', 34 | ]; 35 | } 36 | 37 | /** 38 | * Upon running composer install or update, install the drupal libraries. 39 | * @param Event $event install/update event 40 | */ 41 | public function install(Event $event) { 42 | // get composer object 43 | $composer = $event->getComposer(); 44 | // get root package extra prop 45 | $extra = $composer->getPackage()->getExtra(); 46 | 47 | // do we have any libraries listed? 48 | if (empty($extra[static::EXTRA_PROP]) || !is_array($extra[static::EXTRA_PROP])) { 49 | return; 50 | } 51 | 52 | // get some services 53 | $downloadManager = $composer->getDownloadManager(); 54 | $installationManager = $composer->getInstallationManager(); 55 | 56 | // install each library 57 | foreach ($extra[static::EXTRA_PROP] as $library => $url) { 58 | // create a virtual package for this library 59 | // we don't ask for a version number, so just use "1.0.0" so the package is considered stable 60 | $package = new Package(static::TYPE . '/' . $library, '1.0.0', $url); 61 | // all URLs are assumed to be zips (for now) 62 | $package->setDistType('zip'); 63 | $package->setDistUrl($url); 64 | $package->setType(static::TYPE); 65 | // let composer download and unpack the library for us! 66 | $downloadManager->download($package, $installationManager->getInstallPath($package)); 67 | } 68 | } 69 | 70 | } 71 | --------------------------------------------------------------------------------