Colored output for TTYs, props added

This commit is contained in:
Chris 2017-01-10 15:13:49 +01:00
parent 631e86aa6f
commit bf12eb7b50
6 changed files with 182 additions and 19 deletions

View File

@ -58,6 +58,80 @@ the plugin or library has what is needed, such as checking a define or making
sure that a method or class already exists. sure that a method or class already exists.
## Sources and Stubs
Source files are added in the `include` block as either a `file` or a `dir`.
include {
dir "directory-to-add";
file "file-to-add.php";
}
The stub is what is invoked when the executable is called, and it is defined in
the `phar` block, outside of the `include` block that is. The stub must however
be added through one of the rules in the `include` block.
stub "src/stub.php";
In the future, it will also be possible to exclude files matching specific
patterns.
## Props
The project properties are a set of key=value items that are defined in the stub,
and thus made available to the code in the phar. it can be read from a file, or
generated by a script or executable. Comments should be prefixed with a hash sign
(`#`):
# Comment line
MYAPP_VERSION=1.0
MYAPP_VARIANT=lite
MYAPP_BUILDDATE=2017-03-14
To add props from a file:
props "app.props";
To evaluate props when building the archive:
props exec="generate-props.php";
## Options and Tweaks
Boolean options (such as `verbatim` and `library`) will have their value default
to *true* if omitted. So these two lines will have the same effect:
verbatim;
verbatim true;
The following options are currently available. Read the notes before using them
tho!
### library (bool)
If set, the created phar will be a pure library, intended to be *included* into
other PHP projects. The library mode currently depends on composer, and it will
use `vendor/autoload.php` as the main stub. As such, you need to add any code
you want executed on load to `autoload/files` in your composer.json.
### verbatim (bool)
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.
### compress (bool)
Compress is a legacy option from MakePhar *mk1*, and is not yet implemented. It
will work in a similar fashion to how it did before: The resulting .phar will
be compressed, and the output will have a stub prepended to extract the .phar
into a temporary directory before running. But right now **it does nothing**.
## Pro Tips ## Pro Tips
* You can have multiple `phar` blocks in your `makephar.conf`. This lets * You can have multiple `phar` blocks in your `makephar.conf`. This lets
@ -65,5 +139,5 @@ sure that a method or class already exists.
pick the rule to build tho, but rather all defined phars will be built. pick the rule to build tho, but rather all defined phars will be built.
* MakePhar will minify your files using `php_strip_whitespace()` before adding * MakePhar will minify your files using `php_strip_whitespace()` before adding
them to the archive. This shouldn't be an issue, but if your code depends on them to the archive. This shouldn't be an issue, but if your code depends on
a specific character index in a specific php file, you might want to use a specific character index in a specific php file, you might want to specify
another tool for the time being. the `verbatim` option.

View File

@ -4,9 +4,6 @@ phar "makephar.phar" {
// Set to true to build a library-only phar // Set to true to build a library-only phar
library false; library false;
// Set to 1, 2 or 3 to compress, doesn't work for libraries
compress false;
// Set stub // Set stub
stub "src/bootstrap.php"; stub "src/bootstrap.php";

View File

@ -50,6 +50,9 @@ class Application
$this->printHelp(); $this->printHelp();
return; return;
} }
log_info("MakePhar 2.0 - (c) 2016-2017, NoccyLabs");
if ($this->config->init) { if ($this->config->init) {
if (!file_exists("composer.json")) { if (!file_exists("composer.json")) {
error_log("No composer.json in current directory"); error_log("No composer.json in current directory");

View File

@ -19,6 +19,10 @@ class Manifest
protected $stub = null; protected $stub = null;
/** @var bool If true, the archive will be compressed */ /** @var bool If true, the archive will be compressed */
protected $compress = false; protected $compress = false;
/** @var bool If true, the files will be added without minification */
protected $verbatim = false;
/** @var array Properties to be defined in the main stub */
protected $props = [];
/** /**
* Read manifests from a makephar.sdl file and return all the build targets * Read manifests from a makephar.sdl file and return all the build targets
@ -51,10 +55,13 @@ class Manifest
foreach ($tag->getChildren() as $child) switch ($child->getTagName()) { foreach ($tag->getChildren() as $child) switch ($child->getTagName()) {
case 'library': case 'library':
$mf->setIsLibrary($child->getValue()); $mf->setIsLibrary($child->getValue()?:true);
break; break;
case 'compress': case 'compress':
$mf->setCompression($child->getValue()); $mf->setCompression($child->getValue()?:true);
break;
case 'verbatim':
$mf->setVerbatim($child->getValue()?:true);
break; break;
case 'stub': case 'stub':
$mf->setStubFile($child->getValue()); $mf->setStubFile($child->getValue());
@ -67,6 +74,38 @@ class Manifest
break; break;
} }
break; break;
case 'props':
if ($src = (string)$child->getValue()) {
if (!file_exists($src)) {
log_warn("Property file %s not found", $src);
continue;
}
log_info("Reading props from file %s", $src);
$props = file($src, FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES);
} elseif ($script = (string)$child->getAttribute('exec')) {
log_info("Generating props using %s", $script);
if (fnmatch("*.php",$script)) $script = "php {$script}";
exec($script, $props, $ret);
if ($ret>0) {
log_warn("Script exited with code %d", $ret);
continue;
}
} else {
log_warn("Props specified without either script or src. Properties will not be added.");
continue;
}
foreach ($props as $prop) {
$prop = trim($prop);
// skip comments and empty lines
if ($prop && $prop[0]=='#') continue;
if (strpos($prop,'=')===false) continue;
// extract key/value
list ($k,$v) = explode("=",$prop,2);
log_debug(" prop[%s] = %s", strtoupper($k),$v);
$mf->props[strtoupper($k)] = $v;
}
break;
} }
return $mf; return $mf;
@ -117,6 +156,17 @@ class Manifest
return $this->compress; return $this->compress;
} }
public function setVerbatim($value)
{
$this->verbatim = $value;
return $this;
}
public function getVerbatim()
{
return $this->verbatim;
}
public function addSource($type, $path, array $opts) public function addSource($type, $path, array $opts)
{ {
$this->sources[] = (object)[ $this->sources[] = (object)[
@ -151,4 +201,9 @@ class Manifest
return $items; return $items;
} }
public function getProps()
{
return (array)$this->props;
}
} }

View File

@ -38,7 +38,12 @@ class PharBuilder
{ {
// Create the phar // Create the phar
$phar = new \Phar($this->tempFile); $phar = new \Phar($this->tempFile);
$vo = posix_isatty(STDOUT);
// verbatim add
$verbatim = $this->manifest->getVerbatim();
if ($verbatim) {
log_debug("Note: Creating verbatim archive without minification");
}
// Add files // Add files
log_debug("Adding files to phar archive..."); log_debug("Adding files to phar archive...");
@ -48,20 +53,23 @@ class PharBuilder
foreach ($this->files as $file) { foreach ($this->files as $file) {
$i++; $i++;
$tp = dirname($file->src); $tp = dirname($file->src);
if ($tp!=$lp) { if (($tp!=$lp) && (IS_TTY)) {
$lp=$tp; $lp=$tp;
printf("\r\e[K%d/%d %s", $i, $t, $tp); printf("\r\e[K%d/%d %s", $i, $t, $tp);
} }
if (fnmatch("*.php",$file->src)) {
if (fnmatch("*.php",$file->src) && (!$verbatim)) {
$min = php_strip_whitespace($file->src); $min = php_strip_whitespace($file->src);
$size_tot += filesize($file->src); $size_tot += filesize($file->src);
$size_min += strlen($min); $size_min += strlen($min);
$phar->addFromString($file->dest?:$file->src, $min); $phar->addFromString($file->dest?:$file->src, $min);
} else { } else {
$size_tot += filesize($file->src);
$size_min += filesize($file->src);
$phar->addFile($file->dest?:$file->src, $file->src); $phar->addFile($file->dest?:$file->src, $file->src);
} }
} }
($vo) && printf("\r\e[K"); (IS_TTY) && printf("\r\e[K");
$phar->stopBuffering(); $phar->stopBuffering();
// Helper to format sizes // Helper to format sizes
@ -72,9 +80,13 @@ class PharBuilder
}; };
// Format the status // Format the status
$str_tot = $formatSize($size_tot); $str_tot = $formatSize($size_tot);
$str_min = $formatSize($size_min); if (!$verbatim) {
$str_rat = sprintf("%.2f%%", 100/$str_tot*$str_min); $str_min = $formatSize($size_min);
log_debug("Size: %s, Minified: %s (%s)", $str_tot, $str_min, $str_rat); $str_rat = sprintf("%.2f%%", 100/$str_tot*$str_min);
log_debug("Size: %s, Minified: %s (%s)", $str_tot, $str_min, $str_rat);
} else {
log_debug("Size: %s", $str_tot);
}
// Create stub // Create stub
if ($this->manifest->getIsLibrary()) { if ($this->manifest->getIsLibrary()) {
@ -82,6 +94,9 @@ class PharBuilder
// Create library stub // Create library stub
$stub = '<?php '; $stub = '<?php ';
$stub.= 'require_once __DIR__."/vendor/autoload.php";'; $stub.= '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));
}
if (($stubfile = $this->manifest->getStubFile())) { if (($stubfile = $this->manifest->getStubFile())) {
$stub.= 'require_once __DIR__."/'.ltrim($stubfile,'/').'";'; $stub.= 'require_once __DIR__."/'.ltrim($stubfile,'/').'";';
} }
@ -90,7 +105,11 @@ class PharBuilder
log_debug("Creating application stub..."); log_debug("Creating application stub...");
// Write application stub // Write application stub
$stubfile = $this->manifest->getStubFile(); $stubfile = $this->manifest->getStubFile();
$stub = '<?php require_once __DIR__."/'.ltrim($stubfile,'/').'";'; $stub = '<?php ';
foreach ($this->manifest->getProps() as $k=>$v) {
$stub.= sprintf('define(%s,%s);', var_export($k,true), var_export($v,true));
}
$stub.= 'require_once __DIR__."/'.ltrim($stubfile,'/').'";';
$phar->addFromString("index.php", $stub); $phar->addFromString("index.php", $stub);
// Make the phar stub executable // Make the phar stub executable
$mainstub = $phar->createDefaultStub("index.php"); $mainstub = $phar->createDefaultStub("index.php");
@ -116,7 +135,7 @@ class PharBuilder
if (file_exists($output)) { if (file_exists($output)) {
unlink($output); unlink($output);
} }
log_debug("Writing %s", $output); log_info("Writing %s", $output);
rename($this->tempFile, $output); rename($this->tempFile, $output);
if (!$this->manifest->getIsLibrary()) { if (!$this->manifest->getIsLibrary()) {

View File

@ -6,6 +6,21 @@ class LogFuncs {
if ($bound++) return; if ($bound++) return;
} }
} }
function log_info($fmt,...$arg) { printf("[info] {$fmt}\n", ...$arg); }
function log_debug($fmt,...$arg) { printf("[debg] {$fmt}\n", ...$arg); } if (@empty(STDOUT) || (!posix_isatty(STDOUT))) {
function log_warn($fmt,...$arg) { printf("[warn] {$fmt}\n", ...$arg); } define("LF_INFO", "");
define("LF_DEBUG", "");
define("LF_WARN", "");
define("LF_RESET", "");
define("IS_TTY", false);
} else {
define("LF_INFO", "\e[32;1m");
define("LF_DEBUG", "\e[32m");
define("LF_WARN", "\e[31;1m");
define("LF_RESET", "\e[0m");
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); }