php-makephar/src/MakePhar/Manifest.php

215 lines
6.1 KiB
PHP

<?php
namespace MakePhar;
use Sdl\Parser\SdlParser;
use Sdl\SdlTag;
class Manifest
{
/** @var string Output filename */
protected $output = null;
/** @var int|null Mode to set on output filename */
protected $chmod = null;
/** @var string[] Included files and directories */
protected $sources = [];
/** @var bool If true, build a library instead of executable */
protected $library = false;
/** @var string|null The stub to call on */
protected $stub = null;
/** @var bool If true, the archive will be compressed */
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
* defined in it.
*
* @return Manifest[] The parsed manifests
*/
public static function createFromFile($filename)
{
$root = SdlParser::parseFile($filename);
$ret = [];
foreach ($root->getChildren() as $child) {
$mf = self::createFromSdlTag($child);
$ret[] = $mf;
}
return $ret;
}
/**
* Build a manifest from a SdlTag
*
* @return Manifest The manifest
*/
public static function createFromSdlTag(SdlTag $tag)
{
$mf = new Manifest();
// Output
$mf->setOutput($tag->getValue());
foreach ($tag->getChildren() as $child) switch ($child->getTagName()) {
case 'library':
$mf->setIsLibrary($child->getValue()?:true);
break;
case 'compress':
$mf->setCompression($child->getValue()?:true);
break;
case 'verbatim':
$mf->setVerbatim($child->getValue()?:true);
break;
case 'stub':
$mf->setStubFile($child->getValue());
break;
case 'include':
foreach ($child->getChildren() as $inc) switch ($inc->getTagName()) {
case 'dir':
case 'file':
$mf->addSource($inc->getTagName(),$inc->getValue(),$inc->getAttributeStrings());
break;
}
break;
case 'props':
$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;
}
public function setOutput($output)
{
$this->output = $output;
return $this;
}
public function getOutput()
{
return $this->output;
}
public function setIsLibrary($value)
{
$this->library = (bool)$value;
return $this;
}
public function getIsLibrary()
{
return $this->library;
}
public function setStubFile($file)
{
$this->stub = $file;
return $this;
}
public function getStubFile()
{
return $this->stub;
}
public function setCompression($value)
{
$this->compress = $value;
return $this;
}
public function getCompression()
{
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)
{
$this->sources[] = (object)[
'type' => $type,
'path' => $path,
'opts' => (object)$opts,
];
return $this;
}
public function getSources()
{
return $this->sources;
}
public function findSourceFiles()
{
$items = [];
foreach ($this->sources as $source) {
if ($source->type == 'dir') {
$it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source->path));
foreach ($it as $item) {
if ($item->isDir()) continue;
$items[] = (object)['src'=>$item->getPathname(),'dest'=>null];
}
} elseif ($source->type == 'file') {
$items[] = (object)['src'=>$source->path,'dest'=>null];
} else {
log_warn("Unsupported source type: %s", $source->type);
}
}
$items = array_filter($items, function ($item) {
if (fnmatch("*/.git/*", $item->src)) return false;
return true;
});
return $items;
}
public function getProps()
{
return (array)$this->props;
}
}