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

⌈⌋ ⎇ branch:  cross package maker


-s composer package input

State: testing
Targets: deb, rpm, phar

The composer 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.

fpm -s composer packaging methods

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

  • Individual components

    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.)

  • Pack all the things

    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

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

  • Fetch afresh

    If you're not within a composer checkout, then the -s composer 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

  • Local phars

    Instead of system packages (-t deb and -t rpm) you can also create Phar archives of "vnd-pkg.phar". Simply use the existing -t phar 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.

  • Phars in system packages

    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 --composer-phar 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 for a prototype. (A system trigger can keep the global map updated.)

  • Phar options

    In both cases the -t phar 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.


  • Dependencies

    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.

    • RPM
      • 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.
    • Debian
      • 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 --composer-no-alt is used.
      • Versions are translated to contain orderable ~ and ~~ suffixes for alpha/beta/rc/dev versions, which is what Debians php-pkg-tools does.
    • Phars
      • 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 --no-depends flag.

  • Autoloader building

    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 to build a common autoload.phar. It's both fast and language-compliant (case-insensitive lookups) per default.
    • When generating phar packages, using a --phar-stub 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 for this).

  • Phar attributes

    With --composer-phar or the -t phar 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 -t phar plugin meanwhile bakes a class map into the Phar meta array. It's obviously available for phar bundles and for phar-in-system packages.

    • map
      • class
        • vnd\dir\classname => src/dir/Classname.php
        • myiterator => src/MyIterator.php
      • function
      • const

    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.


See also pkg-php-tools for the Debian build helper (translates package names and dependency lists). Or 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. It was specifically designed for that, is implemented in PHP, and provides more targetted options.

Distinct -u composer update filter

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