Added support for phar metadata

This commit is contained in:
Chris 2017-02-12 02:32:17 +01:00
parent 7ccdb99836
commit 4873ffdf02
9 changed files with 125 additions and 18 deletions

View File

@ -83,6 +83,28 @@ You can follow the same approach when excluding files with the `exclude` block:
The `dir` rules match against `*/<dirname>/*` while the `file` rule will match
against `*/<filename>`.
## 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)

View File

@ -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" ],

View File

@ -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";
}
}

View File

@ -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

12
props.php Normal file
View File

@ -0,0 +1,12 @@
<?php
function app_version() {
$ver = exec("git describe --tags");
$ver = explode("-",$ver);
if (count($ver)>1) {
$ver = array_slice($ver,0,2);
}
return join(".",$ver);
}
printf("%s=%s\n", "APP_VERSION", app_version());

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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 = '<?php ';
$stub.= 'require_once __DIR__."/vendor/autoload.php";';
$stub.= 'file_exists(__DIR__."/vendor/autoload.php") && require_once __DIR__."/vendor/autoload.php";';
foreach ($this->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;
}

View File

@ -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); }
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); }