2017-01-09 02:24:59 +01:00
|
|
|
<?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;
|
2017-01-10 15:13:49 +01:00
|
|
|
/** @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 = [];
|
2017-01-10 16:02:09 +01:00
|
|
|
/** @var array Patterns to exclude */
|
|
|
|
protected $excludes = [];
|
2017-01-09 02:24:59 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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':
|
2017-01-10 16:47:09 +01:00
|
|
|
$val = $child->getValue();
|
|
|
|
if ($val === null) $val = true;
|
|
|
|
$mf->setIsLibrary($val);
|
2017-01-09 02:24:59 +01:00
|
|
|
break;
|
|
|
|
case 'compress':
|
2017-01-10 16:47:09 +01:00
|
|
|
$val = $child->getValue();
|
|
|
|
if ($val === null) $val = true;
|
|
|
|
$mf->setCompression($val);
|
2017-01-10 15:13:49 +01:00
|
|
|
break;
|
|
|
|
case 'verbatim':
|
2017-01-10 16:47:09 +01:00
|
|
|
$val = $child->getValue();
|
|
|
|
if ($val === null) $val = true;
|
|
|
|
$mf->setVerbatim($val);
|
2017-01-09 02:24:59 +01:00
|
|
|
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;
|
2017-01-10 16:02:09 +01:00
|
|
|
case 'exclude':
|
|
|
|
foreach ($child->getChildren() as $inc) switch ($inc->getTagName()) {
|
|
|
|
case 'dir':
|
|
|
|
$val = (string)$inc->getValue();
|
|
|
|
$mf->excludes[] = "*/{$val}/*";
|
|
|
|
break;
|
|
|
|
case 'file':
|
|
|
|
$val = (string)$inc->getValue();
|
|
|
|
$mf->excludes[] = "*/{$val}";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2017-01-10 15:13:49 +01:00
|
|
|
case 'props':
|
2017-01-10 15:33:49 +01:00
|
|
|
$props = [];
|
2017-01-10 15:13:49 +01:00
|
|
|
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;
|
|
|
|
|
2017-01-09 02:24:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-01-10 15:13:49 +01:00
|
|
|
public function setVerbatim($value)
|
|
|
|
{
|
|
|
|
$this->verbatim = $value;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getVerbatim()
|
|
|
|
{
|
|
|
|
return $this->verbatim;
|
|
|
|
}
|
|
|
|
|
2017-01-09 02:24:59 +01:00
|
|
|
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;
|
2017-01-10 17:11:23 +01:00
|
|
|
$items[] = (object)['src'=>realpath($item->getPathname()),'dest'=>$item->getPathname()];
|
2017-01-09 02:24:59 +01:00
|
|
|
}
|
|
|
|
} elseif ($source->type == 'file') {
|
2017-01-10 17:11:23 +01:00
|
|
|
$items[] = (object)['src'=>realpath($source->path),'dest'=>$item->getPathname()];
|
2017-01-09 02:24:59 +01:00
|
|
|
} else {
|
|
|
|
log_warn("Unsupported source type: %s", $source->type);
|
|
|
|
}
|
|
|
|
}
|
2017-01-10 16:02:09 +01:00
|
|
|
$rules = $this->excludes;
|
|
|
|
$before = count($items);
|
|
|
|
$items = array_filter($items, function ($item) use ($rules) {
|
|
|
|
foreach ($rules as $rule) {
|
|
|
|
if (fnmatch($rule, $item->src)) return false;
|
|
|
|
}
|
2017-01-10 15:16:36 +01:00
|
|
|
return true;
|
|
|
|
});
|
2017-01-10 16:02:09 +01:00
|
|
|
$after = count($items);
|
|
|
|
if ($after < $before) {
|
|
|
|
log_debug("Skipped %d files matching exclusion patterns", $before-$after);
|
|
|
|
}
|
2017-01-09 02:24:59 +01:00
|
|
|
return $items;
|
|
|
|
}
|
|
|
|
|
2017-01-10 15:13:49 +01:00
|
|
|
public function getProps()
|
|
|
|
{
|
|
|
|
return (array)$this->props;
|
|
|
|
}
|
|
|
|
|
2017-01-09 02:24:59 +01:00
|
|
|
}
|