39

I'd like to release a PHP library and submit it on Packagist to have it installable via Composer.

My library has the following structure:

lib/
tests/
composer.json
README.md

Basically, whenever I include this library in a project's composer.json, I'd like everything to be copied with the exception of the tests directory, which is cumbersome and is only needed when developing the library itself. It's just a waste of space otherwise (especially when packaging the project for production).

Is it possible to exclude this directory from the library's composer.json?

BenMorel
  • 34,448
  • 50
  • 182
  • 322

4 Answers4

41

This is not possible in Composer. However, there are some ways to do it:

  • When you run the update or install command with --prefer-dist, Composer tries to download the archive on github. You can remove the test directory from the archives by putting this in a .gitattributes file in the root directory of your project:

    Tests/ export-ignore
    
  • Composer will only use the tags on github. Just temporary remove the tests directory when creating a tag will also do the trick.

Wouter J
  • 41,455
  • 15
  • 107
  • 112
  • Excellent, thanks. The `.gitattributes` solution looks promising. Isn't downloading the ZIP from GitHub the default behaviour, though? – BenMorel Jun 12 '13 at 17:58
  • @Benjamin no, it downloads code from a tag, not the zip. You have to use `--prefer-dist` to get the zip (used wrong switch in the anser, fixed know) – Wouter J Jun 12 '13 at 20:55
  • 9
    Actually [this page](http://getcomposer.org/doc/03-cli.md) says: *For stable versions composer will use the `dist` by default.* – BenMorel Jun 13 '13 at 09:42
24

It's possible to control the archive creation by adding exclude patterns in the composer.json file within the archive key. See https://getcomposer.org/doc/04-schema.md#archive for details.

The example given (cited from above URL):

{
    "archive": {
        "exclude": ["/foo/bar", "baz", "/*.test", "!/foo/bar/baz"]
    }
}

The example will include /dir/foo/bar/file, /foo/bar/baz, /file.php, /foo/my.test but it will exclude /foo/bar/any, /foo/baz, and /my.test.

That way you have about the same control that .gitattributes would give you, without having to use Git or affecting any processes that require different settings in said file.

Sven
  • 69,403
  • 10
  • 107
  • 109
  • 1
    Thanks, I read the paragraph you linked to, but I fail to understand *which* archive this targets: as far as I understand, Packagist does not host package archives; instead Composer downloads packages either by cloning the git repo, or from a ZIP archive (usually from GitHub, that I guess only follows `.gitattributes` and not `composer.json`). Does Composer still do that, but consequently deletes the excluded files locally? – BenMorel Feb 19 '18 at 17:17
  • A very good question, I'll investigate. For sure this setting affects the creation of packages during a Satis run. I'm not sure about downloading packages from Github. – Sven Feb 21 '18 at 17:12
  • @Sven Have you investigated? – Finesse Apr 08 '18 at 12:08
  • 3
    I had a very quick look. My impression: Composer has both code for handling `.gitignore/.gitattributes` files as well as the configuration I mentioned above, suggesting that Composer would be at least able to do the processing of these two different exclude pattern sources locally. And it would explain why Satis is also affected, because it simply orchestrates the Composer code that's already there, without adding very much. So the answer seems to be: "Composer is able to exclude locally, if not supported by any external source". If Github's ZIP has more files, I doubt they will get removed. – Sven Apr 09 '18 at 20:57
2

This has been possible since Nov 11, 2015 with https://getcomposer.org/doc/04-schema.md#exclude-files-from-classmaps

Source: https://github.com/composer/composer/issues/4456#issuecomment-155825777

EDIT: Misinterpretation. The above only lets the autoloader ignore the specified paths, it does not actually prevent them from being copied to the filesystem upon install.

Motin
  • 4,853
  • 4
  • 44
  • 51
  • 1
    Thanks for the pointer! I was about to mark your answer as accepted, but after reading the doc, it looks like this is only excluding those files from the autoloader: they would still be present in the archive. This is obviously a first step, however my ultimate goal was to reduce the archive size by removing the test files entirely when installing from Composer. – BenMorel Oct 26 '16 at 09:56
  • 1
    Oh sorry I misinterpreted the question in that case :) So you want something like the "ignore" option in Bower (ignore [array]: An array of paths not needed in production that you want Bower to ignore when installing your package.) - I am not aware of that feature in composer - have you created a feature request on https://github.com/composer/composer/issues ? – Motin Oct 29 '16 at 11:48
2

This can be automated with post-update-cmd the composer.json file within the scripts key:

"scripts": {
    "post-update-cmd": [
        "rm -rf vendor/aura/intl/tests vendor/cakephp/cakephp/tests"
    ],
},

Or use pattern to remove directories:

"scripts": {
    "post-update-cmd": [
        "find vendor/ -type d -regextype posix-extended -iregex '.*/(doc|docs|example|examples|test|tests|tmp)' -print -exec rm -r {} +"
    ],
},
AndreyP
  • 2,510
  • 1
  • 29
  • 17
  • 1
    It should be noted that this only works for root packages. It will not work if the package is installed as a dependency. Here's the relevant GitHub issue: https://github.com/composer/composer/issues/1193 – nburr Mar 08 '20 at 20:55