Home

Awesome

Composer Downloads Plugin

The "Downloads" plugin allows you to download extra files (*.zip or *.tar.gz) and extract them within your package.

Example

Suppose you publish a PHP package foo/bar which relies on an external artifact examplelib-0.1.zip. Place this configuration in the composer.json for foo/bar:

{
  "name": "foo/bar",
  "require": {
    "civicrm/composer-downloads-plugin": "~3 || ~4"
  },
  "extra": {
    "downloads": {
      "examplelib": {
        "url": "https://example.com/examplelib-0.1.zip",
        "path": "extern/examplelib",
        "ignore": ["test", "doc", ".*"]
      }
    }
  }
}

When a downstream user of foo/bar runs composer install, it will fetch and extract the zip file, creating vendor/foo/bar/extern/examplelib.

Release History

Evaluation

The primary strengths of composer-downloads-plugin are:

The "Downloads" plugin is only a download mechanism. Use it to assimilate an external resource as part of a composer package.

The "Downloads" plugin is not a dependency management system. There is no logic to scan registries, resolve transitive dependencies, identify version-conflicts, etc among diverse external resources. If you need that functionality, then you may want a bridge to integrate composer with an external dependency management tool. A few good bridges to consider:

Configuration: Properties

The extra.downloads section contains a list of files to download. Each extra-file has a symbolic ID (e.g. examplelib above) and some mix of properties:

Values in url and path support the following variables:

Configuration: Defaults

You may set default properties for all downloads. Place them under *, as in:

{
  "extra": {
    "downloads": {
      "*": {
        "path": "bower_components/{$id}",
        "ignore": ["test", "tests", "doc", "docs"]
      },
      "jquery": {
        "url": "https://github.com/jquery/jquery-dist/archive/1.12.4.zip"
      },
      "jquery-ui": {
        "url": "https://github.com/components/jqueryui/archive/1.12.1.zip"
      }
    }
  }
}

This example will:

Tips

Known Limitations

If you use downloads in a root-project (or in symlinked dev repo), it will create+update downloads, but it will not remove orphaned items automatically. This could be addressed by doing a file-scan for .composer-downloads (and deleting any orphan folders). Since the edge-case is not particularly common right now, and since a file-scan could be time-consuming, it might make sense as a separate subcommand.

I believe the limitation does not affect downstream consumers of a dependency. In that case, the regular composer install/update/removal mechanics should take care of any nested downloads.

Automated Tests

The tests/ folder includes unit-tests and integration-tests written with PHPUnit. Each integration-test generates a new folder/project with a plausible, representative composer.json file and executes composer install. It checks the output has the expected files.

To run the tests, you will need composer and phpunit in the PATH.

[~/src/composer-downloads-plugin] which composer
/Users/myuser/bin/composer

[~/src/composer-downloads-plugin] which phpunit
/Users/myuser/bin/phpunit

[~/src/composer-downloads-plugin] phpunit
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.

.....                                                               5 / 5 (100%)

Time: 40.35 seconds, Memory: 10.00MB

OK (5 tests, 7 assertions)

The integration tests can be a bit large/slow. To monitor the tests more closesly, set the DEBUG variable, as in:

[~/src/composer-downloads-plugin] env DEBUG=2 phpunit

Local Dev Harness

What if you want to produce an environment which uses the current plugin code - one where you can quickly re-run composer commands while iterating on code?

You may use any of the integration-tests to initialize a baseline environment:

env USE_TEST_PROJECT=$HOME/src/myprj DEBUG=2 phpunit tests/SniffTest.php