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

βŒˆβŒ‹ βŽ‡ branch:  cross package maker


Artifact [86c4b64ee6]

Artifact 86c4b64ee6a745970e7e4485d716099c51e262c7:

  • File lib/fpm/package/phar.rb — part of check-in [0e56b40574] at 2015-01-28 12:50:35 on branch trunk — Introduce `--phar-x` flag to make output .phar file executable right away. Remove extra .unlink() after renaming target package. (user: mario size: 8582)


# api: fpm
# title: PHP Phar target
# description: Chains to PHP for creating a .phar (native/tar/zip) archive
# type: package
# category: target
# version: 0.3
# state: very alpha
# license: MITL
# author: mario#include-once:org
# 
# This packaging target generates simple PHP Phar assemblies. With its
# default stub assuming `__init__.php` for CLI applications, and `index.php`
# as web router. A custom --phar-stub can be set of course.
#
# It honors the output filename, but alternatively allows `--phar-format`
# overriding the packaging format. It flexibly recognizes any concatenation
# of β€žpharΒ·zipΒ·tarβ€œ with β€žgzΒ·bz2β€œ, case-insensitively.
#
#  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
#  β”‚ Extension   β”‚ Archive     β”‚ Compression β”‚ Envelope    β”‚ Use           β”‚
#  β”‚ / Specifier β”‚ Format      β”‚ Per File    β”‚ Compression β”‚ Cases         β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ phar        β”‚ Phar        β”‚ -           β”‚ -           β”‚               β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ phar.gz     β”‚ Phar        β”‚ gzip        β”‚ -           β”‚ general       β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ pharΒ·bz2    β”‚ Phar        β”‚ bzip2       β”‚ -           β”‚               β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ phaZ        β”‚ Phar        β”‚ -           β”‚ gzip        β”‚               β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ phaZ.gz     β”‚ Phar        β”‚ gzip        β”‚ gzip        β”‚ (eschew)      β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ zip         β”‚ Zip         β”‚ -           β”‚ -           β”‚               β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ zip.gz      β”‚ Zip         β”‚ gzip        β”‚ -           β”‚ distribution  β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ zip…bz2     β”‚ Zip         β”‚ bzip2       β”‚ -           β”‚               β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ tar         β”‚ Pax         β”‚ -           β”‚ -           β”‚               β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ tgz         β”‚ Pax         β”‚ -           β”‚ gzip        β”‚               β”‚
#  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
#  β”‚ tar+bz2     β”‚ Pax         β”‚ -           β”‚ bzip2       β”‚ data bundles  β”‚
#  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
#
# ZIPs and TARs can be read by other languages, but contain PHP/phar-specific
# additions (.phar/stub and a signature).
#

require "fpm/package"
require "fpm/util"
require "fileutils"
require "tempfile"
require "json"

# Phar creation (output only)
class FPM::Package::Phar < FPM::Package

  option "--format", "PHAR.gz/TGZ/ZIP", "Phar package type and compression (append .gz/.bz2 for method)", :default=>"PHAR.GZ"
  option "--stub", "STUB.php", "Apply initialization/stub file", :default=>""
  #option "--nocase", :flag, "Lowercase filenames / implicit `-u lcase=*`", :default=>false
  option "--sign", "PEM_FILE", "Sign package with OpenSSL and key from .pem file", :default=>""
  option "--x", :flag, "Set executable bit on phar package", :default=>false, :hidden=>true

  # Invoke PHP for actual packaging process
  def output(output_path)
    output_check(output_path)

    # Build flags
    p = {
      :name   => name,
      :srcdir => staging_path,
      #:nocase => attributes[:phar_nocase],
      :stub   => attributes[:phar_stub_given?] ? attributes[:phar_stub] : "",
      :sign   => attributes[:phar_sign],
    }
    
    # Retain package meta information, either from fpm attributes, or collected :attr hash (src module, formerly :meta)
    defaults = {
      "id" => @name,
      "version" => @version.to_s,
      "epoch" => @epoch.to_s,
      "iteration" => @iteration.to_s,
      "architecture" => @architecture,
      "category" => @category,
      "author" => @maintainer,
      "url" => @url,
      "license" => @license,
    }.delete_if{ |k,v| ["", nil, "default", "http://example.com/no-uri-given"].include? v }
    p[:meta] = attrs.merge(defaults).delete_if{ |k,v| v.empty? }
    
    # Match format specifier/extension onto type/settings
    fmt = (attributes[:phar_format] + output_path).downcase
    fmt, enc = fmt.match(/zip|phaz|tar|t[gb]z|pz/).to_s||"phar", fmt.match(/gz|bz2/).to_s
    map_keys = [:stdext, :format, :filegz, :extout, :hullgz]
    map = {
        # fmt,  enc          extension   format        per-file-gz   extns ← archive-compr
       ["phar", ""   ] => [ ".phar",     "Phar::PHAR", "Phar::NONE", "",     "" ],
       ["phar", "gz" ] => [ ".phar",     "Phar::PHAR", "Phar::GZ",   "",     "" ],
       ["phar", "bz2"] => [ ".phar",     "Phar::PHAR", "Phar::BZ2",  "",     "" ],
       ["zip",  ""   ] => [ ".phar.zip", "Phar::ZIP",  "Phar::NONE", "",     "" ],
       ["zip",  "gz" ] => [ ".phar.zip", "Phar::ZIP",  "Phar::GZ",   "",     "" ],
       ["zip", "bz2" ] => [ ".phar.zip", "Phar::ZIP",  "Phar::BZ2",  "",     "" ],
       ["tar",  ""   ] => [ ".phar.tar", "Phar::TAR",  "Phar::NONE", "",     "" ],
       ["tar",  "gz" ] => [ ".phar.tar", "Phar::TAR",  "Phar::GZ",   ".gz",  "Phar::GZ" ],
       ["tar", "bz2" ] => [ ".phar.tar", "Phar::TAR",  "Phar::BZ2",  ".bz2", "Phar::BZ2"],
       ["phaz", ""   ] => [ ".phar",     "Phar::PHAR", "Phar::GZ",   ".gz",  "Phar::GZ" ],
       ["phaz", "gz" ] => [ ".phar",     "Phar::PHAR", "Phar::GZ",   ".gz",  "Phar::GZ" ],
       ["phaz", "bz2"] => [ ".phar",     "Phar::PHAR", "Phar::GZ",   ".bz2", "Phar::BZ2"],
    }
    ext2map = {  # map file extensions
       "tgz" => ["tar", "gz"],
       "tbz" => ["tar", "bz2"],
       "pz"  => ["phaz", ""]
    }
    opt = map[[fmt,enc]] || map[ext2map[fmt]] || map[["phar", ""]]
    p.merge! Hash[map_keys.zip opt]

    # Have PHP generate the package
    p[:tmpf] = ::Dir::Tmpname.create(['_\$fpm_phar_', p[:stdext]]) {}
    phargen = template_dir + "/phar.php"
    safesystem("php", "-dphar.readonly=0", "-derror_reporting=~0", "-ddisplay_errors=1", phargen, JSON.generate(p))

    #-- but might end up with suffix, for whole-archive ->compress()ion
    FileUtils.mv(p[:tmpf] + p[:extout], output_path)
    FileUtils.chmod("a+x", output_path) if attributes[:phar_x_given?]
  end

end # class FPM::Package::Phar