Cross package maker. DEB/RPM generation or conversion. Derived from jordansissel/fpm.

⌈⌋ ⎇ branch:  cross package maker


Artifact [ab18f34d7e]

Artifact ab18f34d7e25a26454b7e843cb33f7940ed992f8:

Wiki page [source_composer] by mario 2015-01-28 12:35:46.
D 2015-01-28T12:35:46.182
L source_composer
N text/x-markdown
P d080baf194d9edab932ba656a4d7301b7140a30e
U mario
W 9755
## <kbd>*-s* `composer`</kbd> package input

<small>State: *testing*  
Targets: *deb*, *rpm*, *phar*</small>

The <kbd>composer</kbd> plugin can turn composer bundles into system packages (`deb`/`rpm`). They extract libraries under `/usr/share/php/` then. Alternatively you can create local phars, or phars wrapped into system packages.

<img src="raw/c8a3139c59fbe88cd5f1844e2b2083426ada825c?m=image/png" alt="fpm -s composer packaging methods" width=850 height=222>

Normally you'd just use composer directly for joining libraries into projects. Syspackaging is meant to further fixate dependencies as globally shared libraries. Having php includes under system control can simplify deployment in a few settings.

## System packages

 * <h2> Individual components </h2>
    
    To package a dependency from within a composer-managed project directory use:

         xpm  -s composer  -t deb,rpm  gregwar/formidable

    Note that fpm/xpm is meant for crafting one package at a time. So this will output exactly one `*.deb` / `*.rpm` package. If you specified more than one composer bundle name as input, they'd end up intermingled otherwise. (→ A warning will occur, and fpm aborts.)


 * <h3> Pack all the things </h3>

    However it's quite trivial to convert all composer dependencies at once with a shell loop:

        for P in vendor/*/*; do
           xpm  -s composer  -t deb  $P
        done

    This will create a whole bunch of `php-vnd-pkg_0.1.2_all.deb` system packages.


 * <h3> Fetch afresh </h3>

    If you're not within a composer checkout, then the <kbd>-s composer</kbd> hook will of course retrieve it directly via composer and from packagist. This way you could also predefine a version:

         xpm -s composer -t deb --composer-ver 2.7  new/new

    Again, this will just convert one individual package. It will have its system `Depends:` field populated. But its actual dependent packages must be crafted this way too/manually. (It's most practicaly to just create an empty directory, checkout a complete package list per `composer install`, and then use the `for`-loop method to package every component in one run.)


## Pack'ging Phars

 * <h2>Local phars </h2>

     Instead of system packages (`-t deb` and `-t rpm`) you can also create Phar archives of "`vnd-pkg.phar`". Simply use the existing <kbd>`-t phar`</kbd> target:
     
         xpm -s composer -t phar  vendor/vnd/pkg
     
     Such phar archives of course won't contain absolute paths. In fact all source files are assembled without any ./vnd/pkg/ prefixes. → That would be redundant because it's already obvious from the phar basename (and its archive meta data).

     Using phar packages within projects of course requires a modern autoloader. Be advised that it's a super negligible performance benefit by itself. Generally classmap-based autoloaders can be faster. But if class dependencies are dispersed across files within, then there's little gain over entirely file-by-file-tapping ones.


 * <h2> Phars in system packages </h2>

     An interesting variation for the packaging process is to convert Composer packages into Phars wrapped in system packages. (This is labeled "matroska" mode in the plugin, btw). And it's simply available per <kbd>`--composer-phar`</kbd> flag:

         xpm -s composer --composer-phar -t deb,rpm  new/new

     This way you'll end up with a system `phar-vnd-pkg_0.1_all.deb`/`.rpm` package. Which will install its contained `Vnd-Pkg.phar` directly under `/usr/share/php/`.

     Again you'd need an autoloader that's designed for this. See [shared.phar](http://fossil.include-once.org/canonic_autoloader/) for a prototype. (A system trigger can keep the global map updated.)


 * <h3> Phar options </h3>

    In both cases the <kbd>[-t phar](wiki/phar)</kbd> module is used (internally) for generation. Currently and per default the composer source hook predefines the Phar format to be of the inspectable/compressed `ZIP+gz` variety. You could alternatively set the `--phar-format=phar` for native/uncompressed Phars of course.


## Notes 


 * <h4> Dependencies </h4>

     Composer package relations are transformed into `Depends:`/`Requires:` fields, with package names remapped to `php-vnd-pkg (>= 1.0)` for example. Not all composer versioning internas are translated however, because RPM support for alternatives is mostly non-existent, and Debian has other guidelines as well.

      * <h5>RPM</h5>

         * Package names are `php-vnd-pkg_1.0.rpm`
         * Requires become `php-composer(vnd/pkg) >= 1.0` lists.
         * Version state appendices are cut out completely, as assumed [from Fedora examples](http://rpms.famillecollet.com/rpmphp/rpm.php?type=composer).

      * <h5>Debian</h5>

         * Packages become `php-vnd-pkg-1.0.deb`
         * Dependencies are listed as `php-vnd-pkg`, but alternatively allows `phar-vnd-pkg` for any package, unless <kbd>--composer-no-alt</kbd> is used.
         * Versions are translated to contain orderable `~` and `~~` suffixes for alpha/beta/rc/dev versions, which is what [Debians php-pkg-tools](http://pkg-php.alioth.debian.org/) does.

      * <h5>Phars</h5>

         * Unprefixed package names `vnd-pkg.phar`
         * Depends: `vnd-pkg >= 1.0, two-lib >= 2.0` are basically local URNs.
         * Versions are only minimally adapted to be suitable for PHPs native `version_compare()`.

     There's support for comparative, tilde and caret version expressions, some literals, also for conflicts and provides. Non-development releases should be preferred still. And in case of dependency hell, use fpms <kbd>`--no-depends`</kbd> flag.



 * <h4> Autoloader building </h4>

    The current version doesn't predefine any specific autoloader regeneration. This leaves room for a few options though.

       * On Debian systems a package trigger watching for `/usr/share/php/` would certainly be the best option. This rebuilds any classloader after installations there.

       * Preferrably use [**phpab**](https://github.com/theseer/Autoload) to build a common `autoload.phar`. It's both fast and language-compliant (case-insensitive lookups) per default.

       * When generating `phar` packages, using a <kbd>--phar-stub</kbd> for a concrete and built-in autoload registration is an option. A simple `include("vnd-pkg.phar");` could then initialize dependencies explicitly.

       * The aforementioned `shared.phar` prototype would also work. In fact implements the package/directory trigger. (The RPM trigger is untested still. Just recently transition to a `fpm` package build script.)

    **Obsolete**: Formerly `composer.lock` information was retained in each packages `composer.json` under `extra[]→lock{}`. But composer itself doesn't support rebuilding `composer.lock` or thus its autoloader. Both Debian and Fedora decided against `vendor/*/*` beneath `/usr/share/php`, and composer folks never wanted it either. Therefore the current xpm composer plugin doesn't allow that anymore. (See the attachment for a prior rough implementation of composer.lock and autoloader/installed.json reconstruction; or the opensuse workaround: [composer-add-package](https://gist.github.com/thomascube/9117025) for this).


 * <h4> Phar attributes </h4>

     With <kbd>--composer-phar</kbd> or the <kbd>-t phar</kbd> target, each generated archive contains an archive meta data bag. It's intended for simple application-level feature/plugin management, similar to a pre-parsed `composer.json` even. The fields `id:` and `version:`, as well as `title:`, `description:`, `author:`, `url:`, `category:` are available.

     Dependencies are translated into basename `depends:` lists. A copy of composer fields is retained in a `composer: {}` instead. (Redundant, as the composer.json is also packaged within. But may be more convenient in some cases.)

 * built-in **Classmap** for Phars

    The <kbd><a href="wiki/phar">-t phar</a></kbd> plugin meanwhile bakes a class map into the Phar meta array. It's obviously available for phar bundles and for phar-in-system packages.

       * <kbd>map</kbd>
          * <kbd>class</kbd>
             * `vnd\dir\classname` **=>** `src/dir/Classname.php`
             * `myiterator` **=>** `src/MyIterator.php`
          * <kbd>function</kbd>
          * <kbd>const</kbd>

    Most autoloaders would only consume the `class` attributes of course. Canonic_Autoloader is prepared to `addPhar()` this structure to the active classmap. Identifiers are already lowercased for language-compliant autoloading, of course.



<h3> Alternatives </h3>

 See also [`pkg-php-tools`](https://packages.debian.org/de/sid/pkg-php-tools) for the Debian build helper (translates package names and dependency lists). Or [`php-composer-rpms`](https://github.com/siwinski/php-composer-rpms) for creating `rpm` packages (seems to be a stub though).

 If you're just looking for a way to bundle up *all* project dependencies at once, then instead check out [github:clue/phar-composer](https://github.com/clue/phar-composer). It was specifically designed for that, is implemented in PHP, and provides more targetted options.


 <h4> Distinct -u composer update filter </h4>

 Note that the `-s composer` source plugin has a distinct purpose to the [<kbd>*-u* composer</kbd>](wiki/update_composer) filter. The -update filter only generates a stub `composer.json` and is intended for plain `phar` archives generated from <kbd>-s dir</kbd> source files or <kbd>-s src</kbd> for meta-tagged scripts. -- Both plugin types are not yet aligned in any way; so you don't want to combine them.


Z 4c76fd16af23dd4750c5c240445a4367