Skip to content

Instantly share code, notes, and snippets.

@prof-milki
Last active August 29, 2015 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prof-milki/1c1930b2e8cba5753902 to your computer and use it in GitHub Desktop.
Save prof-milki/1c1930b2e8cba5753902 to your computer and use it in GitHub Desktop.
Phar target package
# api: fpm
# title: PHP Phar target
# description: Chains to PHP for creating a .phar (native/tar/zip) archive
# type: package
# category: target
# version: 0.2
# 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 │ │
# ├─────────────┼─────────────┼─────────────┼─────────────┼───────────────┤
# │ - │ 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 "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 within archive", :default=>false
option "--sign", "PEM_FILE", "Sign package with OpenSSL and key from .pem file", :default=>""
# Invoke PHP for actual packaging process
def output(output_path)
# Flags
nocase = attributes[:phar_nocase] || false
stub = attributes[:phar_stub] || ""
sign = attributes[:phar_sign] || ""
# Retain package meta information, either from fpm attributes, or collected :meta hash (src module)
meta = attributes[:meta] || {
"id" => @name,
"version" => @version.to_s,
"epoch" => @epoch.to_s,
"iteration" => @iteration.to_s,
"architecture" => @architecture,
"category" => @category == "none" ? nil : @category,
"author" => @maintainer,
"url" => @url,
"license" => @license,
}
meta = meta.delete_if{ |k,v| v.nil? || v==""}
# 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
map2 = { "tgz" => ["tar", "gz"], "tbz" => ["tar", "bz2"], "pz" => ["phaz", ""] }
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)"],
}
opt = map[[fmt,enc]] || map[map2[fmt]] || map[["phar", ""]]
# File list
output_check(output_path)
output_phar = File.dirname(output_path) + "/_\$tmp_phar" + opt[0]
output_check(output_phar)
File.unlink(output_phar) if File.exists?(output_phar)
# Have PHP generate the package
code = <<-PHP
#-- Create phar
$p = new Phar('#{output_phar}', 0, '#{name}');
$p->startBuffering();
#-- Add files
$p->buildFromDirectory('#{staging_path}');
#-- Stub
if (strlen('#{stub}') && file_exists('#{staging_path}/#{stub}')) {
$p->setStub(file_get_contents('#{staging_path}/#{stub}'));
}
else {
$p->setDefaultStub("__init__.php", "index.php");
}
#-- Carry packaging info over as meta data (in particular for `fpm -s src` module)
$p->setMetadata(json_decode($_SERVER["argv"][1]));
#-- Per-file compression
if (#{opt[2]}) {
$p->compressFiles(#{opt[2]});
}
#-- Signature
if (strlen('#{sign}')) {
$p->setSignatureAlgorithm(Phar::OPENSSL, file_get_contents('#{sign}'));
}
else {
$p->setSignatureAlgorithm(Phar::SHA256);
}
#-- Save all the things
$p->stopBuffering();
// Whole-archive compression; output goes to a different filename. (Cleaned up in Ruby...)
if ("#{opt[3]}") {
$p->compress(#{opt[4]});
}
PHP
safesystem("php", "-dphar.readonly=0", "-r", code, JSON.generate(meta))
#-- but might end up with suffix, for whole-archive ->compress()ion
File.rename(output_phar + opt[3], output_path)
File.unlink(output_phar) if File.exists?(output_phar)
end
end # class FPM::Package::Phar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment