From 4873ffdf02aec657875eed7599c095dbabbc75a0 Mon Sep 17 00:00:00 2001 From: Christopher Vagnetoft Date: Sun, 12 Feb 2017 02:32:17 +0100 Subject: [PATCH] Added support for phar metadata --- README.md | 24 ++++++++++++++++++++++ composer.json | 3 ++- makephar.sdl | 10 ++++++++- makephar.sdl.dist | 9 +++++++- props.php | 12 +++++++++++ src/MakePhar/Application.php | 28 +++++++++++++++++-------- src/MakePhar/Manifest.php | 40 ++++++++++++++++++++++++++++++++++-- src/MakePhar/PharBuilder.php | 11 ++++++++-- src/global.php | 6 +++--- 9 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 props.php diff --git a/README.md b/README.md index f9628a1..f97a9f3 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,28 @@ You can follow the same approach when excluding files with the `exclude` block: The `dir` rules match against `*//*` while the `file` rule will match against `*/`. +## Metadata + +As PHAR archives support metadata, you can insert your own custom data using +the `metadata` block: + + library; // build a library (plugin) + metadata { + plugin_type "myapp.plugin"; + plugin_name "myapp.plugin.awesomeplugin"; + plugin_version "1.0.0"; + } + +You can also map props to metadata. The advantage to this is that you can scan +the metadata before including the .phar letting you pick the most recent versions +etc. + + metadata { + plugin_version prop="MYPLUGIN_VERSION"; + } + +The order is important! Make sure you have defined the props you want to reference +before referencing them! ## Props @@ -142,6 +164,8 @@ If set, no minification will take place. Generally, the minification should not cause any problems but lead to a file that can be up to half a megabyte smaller as whitespace and comments are removed. +It is also possible to mark specific directories or files as verbatim on the +`dir` and `file` tags in an `include` block. ### compress (bool) diff --git a/composer.json b/composer.json index 43d891e..d94140f 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ ], "require": { "noccylabs/sdl": "^2.0", - "symfony/finder": "^3.2" + "symfony/finder": "^3.2", + "noccylabs/tinyphar": "^0.1.1" }, "autoload": { "files": [ "src/global.php" ], diff --git a/makephar.sdl b/makephar.sdl index 100b2ab..11f3de7 100644 --- a/makephar.sdl +++ b/makephar.sdl @@ -4,14 +4,22 @@ phar "makephar.phar" { // Set stub stub "src/bootstrap.php"; + props exec="props.php"; + + metadata { + package_name "makephar.application"; + package_version prop="APP_VERSION"; + update_channel "https://packages.noccylabs.info/channel/makephar/testing.json"; + } + // Select files/dirs to include include { dir "vendor"; dir "src"; } - exclude { dir ".git"; + dir "Tests"; } } diff --git a/makephar.sdl.dist b/makephar.sdl.dist index 97b16fe..8b7e4ac 100644 --- a/makephar.sdl.dist +++ b/makephar.sdl.dist @@ -10,10 +10,17 @@ phar "output.phar" { // Define the stub called when the phar is executed stub "src/bootstrap.php"; + // Phar metadata + metadata { + generator "MakePhar/2.0"; + channel_stable "http://dist.noccylabs.info/channels/makephar/stable.json"; + channel_beta "http://dist.noccylabs.info/channels/makephar/beta.json"; + } + // Select files/dirs to include include { dir "vendor"; - dir "src"; + dir "src" verbatim=true; /* directories and files can be marked verbatim */ } // Patterns to exclude diff --git a/props.php b/props.php new file mode 100644 index 0000000..d38864f --- /dev/null +++ b/props.php @@ -0,0 +1,12 @@ +1) { + $ver = array_slice($ver,0,2); + } + return join(".",$ver); +} + +printf("%s=%s\n", "APP_VERSION", app_version()); diff --git a/src/MakePhar/Application.php b/src/MakePhar/Application.php index 38d0653..ab093e0 100644 --- a/src/MakePhar/Application.php +++ b/src/MakePhar/Application.php @@ -9,7 +9,7 @@ class Application private function parseCommandLine() { - $opts = "hn"; + $opts = "hnq"; $long = [ 'help', 'new' ]; $parsed = getopt($opts, $long); @@ -19,6 +19,7 @@ class Application 'manifest' => getcwd()."/makephar.sdl", 'output' => null, 'compress' => false, + 'quiet' => false, ]; foreach ($parsed as $k=>$v) switch ($k) { @@ -30,6 +31,9 @@ class Application case 'new': $config['init'] = true; break; + case 'q': + $config['quiet'] = true; + break; } $this->config = (object)$config; @@ -40,19 +44,22 @@ class Application printf("Usage: makephar [opts]\n"); printf("Options: -h,--help Show this help\n"); printf(" -n,--new Create a new configuration file\n"); + printf(" -q Quiet operation\n"); } public function run() { $this->parseCommandLine(); + if ($this->config->quiet) { + define("QUIET",true); + } + if ($this->config->help) { $this->printHelp(); return; } - log_info("MakePhar 2.0 - (c) 2016-2017, NoccyLabs"); - if ($this->config->init) { if (!file_exists("composer.json")) { error_log("No composer.json in current directory"); @@ -62,6 +69,9 @@ class Application $proj_name = basename(getcwd()).".phar"; $proj_files = []; $proj_dirs = []; + printf("// makephar.sdl generated for %s\n", basename(getcwd())); + printf("phar \"%s\" {\n", $proj_name); + printf(" include {\n"); if (!empty($proj->autoload)) { foreach ((array)$proj->autoload as $type=>$loaders) { if ($type == 'files') { @@ -75,20 +85,22 @@ class Application } } } - printf("phar \"%s\" {\n", $proj_name); - printf(" include {\n"); foreach ($proj_files as $file) printf(" file \"%s\";\n", $file); foreach ($proj_dirs as $dir) printf(" dir \"%s\";\n", $dir); printf(" dir \"vendor\";\n"); - printf(" }\n"); - printf(" // stub \"src/path-to-stub.php\";\n"); - printf("}\n"); + } else { + printf(" // file \"filename.php\" src=\"path/file.php\";\n"); + printf(" // dir \"path\";\n"); } + printf(" }\n"); + printf(" // stub \"src/path-to-stub.php\";\n"); + printf("}\n"); return; } + log_info("MakePhar 2.0 - (c) 2016-2017, NoccyLabs"); $this->buildManifest(); } diff --git a/src/MakePhar/Manifest.php b/src/MakePhar/Manifest.php index b99d875..b01705f 100644 --- a/src/MakePhar/Manifest.php +++ b/src/MakePhar/Manifest.php @@ -25,6 +25,8 @@ class Manifest protected $props = []; /** @var array Patterns to exclude */ protected $excludes = []; + /** @var array Phar metadata */ + protected $metadata = []; /** * Read manifests from a makephar.sdl file and return all the build targets @@ -94,6 +96,21 @@ class Manifest break; } break; + case 'metadata': + foreach ($child->getChildren() as $meta) { + if (($prop = $meta->getAttribute("prop"))) { + if (array_key_exists($prop,$mf->props)) { + $value = $mf->props[$prop]; + } else { + log_warn("Property %s is not defined", $prop); + } + } else { + $value = $meta->getValue(); + } + $mf->setMetadata($meta->getTagName(), $value); + + } + break; case 'props': $props = []; if ($src = (string)$child->getValue()) { @@ -166,6 +183,20 @@ class Manifest return $this->stub; } + public function setMetadata($key,$value) + { + $this->metadata[$key] = $value; + } + + public function getMetadata($key=null) + { + if ($key===null) + return $this->metadata; + if (!array_key_exists($key, $this->metadata)) + return null; + return $this->metadata[$key]; + } + public function setCompression($value) { $this->compress = $value; @@ -207,14 +238,19 @@ class Manifest { $items = []; foreach ($this->sources as $source) { + if (@isset($source->opts->verbatim)) { + $verbatim = $source->opts->verbatim; + } else { + $verbatim = $this->getVerbatim(); + } if ($source->type == 'dir') { $it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source->path)); foreach ($it as $item) { if ($item->isDir()) continue; - $items[] = (object)['src'=>realpath($item->getPathname()),'dest'=>$item->getPathname()]; + $items[] = (object)['src'=>realpath($item->getPathname()),'dest'=>$item->getPathname(),'verbatim'=>$verbatim]; } } elseif ($source->type == 'file') { - $items[] = (object)['src'=>realpath($source->path),'dest'=>$item->getPathname()]; + $items[] = (object)['src'=>realpath($source->path),'dest'=>$source->path,'verbatim'=>$verbatim]; } else { log_warn("Unsupported source type: %s", $source->type); } diff --git a/src/MakePhar/PharBuilder.php b/src/MakePhar/PharBuilder.php index d9d8136..c984a58 100644 --- a/src/MakePhar/PharBuilder.php +++ b/src/MakePhar/PharBuilder.php @@ -59,7 +59,7 @@ class PharBuilder } $size_tot += filesize($file->src); - if (fnmatch("*.php",$file->src) && (!$verbatim)) { + if (fnmatch("*.php",$file->src) && (!$file->verbatim)) { $min = php_strip_whitespace($file->src); $size_min += strlen($min); $phar->addFromString($file->dest?:$file->src, $min); @@ -92,7 +92,7 @@ class PharBuilder log_debug("Creating library stub..."); // Create library stub $stub = 'manifest->getProps() as $k=>$v) { $stub.= sprintf('define(%s,%s);', var_export($k,true), var_export($v,true)); } @@ -119,6 +119,13 @@ class PharBuilder $phar->setStub($mainstub); } + // Write metadata + log_debug("Writing metadata..."); + $md = $this->manifest->getMetadata(); + foreach ($md as $key=>$value) + log_debug(" meta[{$key}] = {$value}"); + $phar->setMetadata($md); + // Close the phar $phar = null; } diff --git a/src/global.php b/src/global.php index 4e42dac..64e5a9c 100644 --- a/src/global.php +++ b/src/global.php @@ -21,6 +21,6 @@ if (@empty(STDOUT) || (!posix_isatty(STDOUT))) { define("IS_TTY", true); } -function log_info($fmt,...$arg) { printf(LF_INFO."[info] {$fmt}".LF_RESET."\n", ...$arg); } -function log_debug($fmt,...$arg) { printf(LF_DEBUG."[debg] {$fmt}".LF_RESET."\n", ...$arg); } -function log_warn($fmt,...$arg) { printf(LF_WARN."[warn] {$fmt}".LF_RESET."\n", ...$arg); } \ No newline at end of file +function log_info($fmt,...$arg) { defined("QUIET") || printf(LF_INFO."[info] {$fmt}".LF_RESET."\n", ...$arg); } +function log_debug($fmt,...$arg) { defined("QUIET") || printf(LF_DEBUG."[debg] {$fmt}".LF_RESET."\n", ...$arg); } +function log_warn($fmt,...$arg) { defined("QUIET") || printf(LF_WARN."[warn] {$fmt}".LF_RESET."\n", ...$arg); }