Added command line option to init config file
This commit is contained in:
parent
cd3e399e55
commit
dd0e6c6b58
31
bin/pharlite
31
bin/pharlite
@ -14,12 +14,14 @@ if (posix_isatty(STDOUT)) {
|
|||||||
define("FMT_ERR", "\e[31;1m");
|
define("FMT_ERR", "\e[31;1m");
|
||||||
define("FMT_WARN", "\e[33;1m");
|
define("FMT_WARN", "\e[33;1m");
|
||||||
define("FMT_INFO", "\e[32m");
|
define("FMT_INFO", "\e[32m");
|
||||||
|
define("FMT_NOTICE", "\e[33m");
|
||||||
define("FMT_AFTER", "\e[0m");
|
define("FMT_AFTER", "\e[0m");
|
||||||
} else {
|
} else {
|
||||||
define("FMT_ERR", "");
|
define("FMT_ERR", "");
|
||||||
define("FMT_WARN", "");
|
define("FMT_WARN", "");
|
||||||
define("FMT_INFO", "");
|
define("FMT_INFO", "");
|
||||||
define("FMT_AFTER", "");
|
define("FMT_AFTER", "");
|
||||||
|
define("FMT_NOTICE", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function print_error($fmt, ...$arg) {
|
function print_error($fmt, ...$arg) {
|
||||||
@ -34,24 +36,33 @@ function print_info($fmt, ...$arg) {
|
|||||||
fprintf(STDOUT, FMT_INFO.$fmt.FMT_AFTER.PHP_EOL, ...$arg);
|
fprintf(STDOUT, FMT_INFO.$fmt.FMT_AFTER.PHP_EOL, ...$arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function print_notice($fmt, ...$arg) {
|
||||||
|
fprintf(STDOUT, FMT_NOTICE.$fmt.FMT_AFTER.PHP_EOL, ...$arg);
|
||||||
|
}
|
||||||
|
|
||||||
function show_app_usage() {
|
function show_app_usage() {
|
||||||
printf("usage\n");
|
printf("options:\n");
|
||||||
|
printf(" -I,--init Initialize a new configuration\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse_opts() {
|
function parse_opts() {
|
||||||
|
|
||||||
$opts = getopt(
|
$opts = getopt(
|
||||||
"ho:d:i",
|
"ho:d:iI",
|
||||||
[
|
[
|
||||||
"help",
|
"help",
|
||||||
"directory:",
|
"directory:",
|
||||||
"dir:",
|
"dir:",
|
||||||
"output:",
|
"output:",
|
||||||
"install"
|
"install",
|
||||||
|
"init"
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$parsed = [];
|
$parsed = [
|
||||||
|
'install' => false,
|
||||||
|
'init' => false
|
||||||
|
];
|
||||||
|
|
||||||
foreach ($opts as $option=>$value) {
|
foreach ($opts as $option=>$value) {
|
||||||
switch ($option) {
|
switch ($option) {
|
||||||
@ -71,6 +82,10 @@ function parse_opts() {
|
|||||||
case 'i':
|
case 'i':
|
||||||
case 'install':
|
case 'install':
|
||||||
$parsed['install'] = true;
|
$parsed['install'] = true;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
case 'init':
|
||||||
|
$parsed['init'] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,11 +93,15 @@ function parse_opts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$opts = parse_opts();
|
$opts = parse_opts();
|
||||||
if (false === parse_opts()) {
|
if (false === $opts) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = getcwd();
|
$path = getcwd();
|
||||||
|
|
||||||
$builder = new PharLite\Builder($path, $opts);
|
$builder = new PharLite\Builder($path, $opts);
|
||||||
$builder->build();
|
if ($opts['init']) {
|
||||||
|
$builder->initConfig();
|
||||||
|
} else {
|
||||||
|
$builder->build();
|
||||||
|
}
|
||||||
|
@ -19,5 +19,10 @@
|
|||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"bin/pharlite"
|
"bin/pharlite"
|
||||||
]
|
],
|
||||||
|
"extra": {
|
||||||
|
"phar": {
|
||||||
|
"output": "pharlite"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
121
src/Builder.php
121
src/Builder.php
@ -44,6 +44,7 @@ class Builder
|
|||||||
self::$default_options,
|
self::$default_options,
|
||||||
$opts
|
$opts
|
||||||
);
|
);
|
||||||
|
$this->path = $path;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,26 +53,24 @@ class Builder
|
|||||||
{
|
{
|
||||||
print_info("Parsing composer.json...");
|
print_info("Parsing composer.json...");
|
||||||
|
|
||||||
$json = file_get_contents("composer.json");
|
$json = file_get_contents($this->path."/composer.json");
|
||||||
|
|
||||||
$composer = json_decode($json);
|
$composer = json_decode($json);
|
||||||
|
|
||||||
if (!isset($composer->bin) || !is_array($composer->bin)) {
|
if (!isset($composer->bin) || !is_array($composer->bin)) {
|
||||||
print_warn("No executable defined, building a library phar...");
|
print_warn("No executable defined, building a library phar...");
|
||||||
} elseif (count($composer->bin)>1) {
|
} elseif (count($composer->bin)>1) {
|
||||||
print_info("More than one executable defined, using the first one as default");
|
print_notice("More than one executable defined, using the first one as default");
|
||||||
print_info(" → Using executable %s", $composer->bin[0]);
|
print_info(" → Using default executable %s", $composer->bin[0]);
|
||||||
|
for ($n = 1; $n < count($composer->bin); $n++) {
|
||||||
|
print_info(" → Adding alternate executable %s", $composer->bin[$n]);
|
||||||
|
}
|
||||||
$this->bins = $composer->bin;
|
$this->bins = $composer->bin;
|
||||||
} else {
|
} else {
|
||||||
print_info(" → Using executable %s", $composer->bin[0]);
|
print_info(" → Using executable %s", $composer->bin[0]);
|
||||||
$this->bins = $composer->bin;
|
$this->bins = $composer->bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($composer->extra) && isset($composer->extra->phar)) {
|
|
||||||
print_info(" → Found extra phar configuration");
|
|
||||||
$this->pharOpts = (array)$composer->extra->phar;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->index) {
|
if ($this->index) {
|
||||||
$this->pharType = self::PHAR_TYPE_WEB;
|
$this->pharType = self::PHAR_TYPE_WEB;
|
||||||
$this->output = basename($this->index,".php").".phar";
|
$this->output = basename($this->index,".php").".phar";
|
||||||
@ -81,6 +80,20 @@ class Builder
|
|||||||
}
|
}
|
||||||
$this->output = "output.phar";
|
$this->output = "output.phar";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($composer->extra)) {
|
||||||
|
if (isset($composer->extra->phar)) {
|
||||||
|
print_info(" → Found extra phar configuration");
|
||||||
|
$this->pharOpts = (array)$composer->extra->phar;
|
||||||
|
}
|
||||||
|
if (array_key_exists('output', $this->pharOpts)) {
|
||||||
|
$this->output = $this->pharOpts['output'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('stub', $this->pharOpts)) {
|
||||||
|
// set a custom stub
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print_info("Generating output %s", $this->output);
|
print_info("Generating output %s", $this->output);
|
||||||
|
|
||||||
$this->composer = $composer;
|
$this->composer = $composer;
|
||||||
@ -96,7 +109,17 @@ class Builder
|
|||||||
{
|
{
|
||||||
print_info("Creating manifest...");
|
print_info("Creating manifest...");
|
||||||
|
|
||||||
|
$excluded = (array)(
|
||||||
|
array_key_exists('exclude',$this->pharOpts)
|
||||||
|
?$this->pharOpts['exclude']
|
||||||
|
:[]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
$manifest = new Manifest($this->path);
|
$manifest = new Manifest($this->path);
|
||||||
|
|
||||||
|
$manifest->setExcluded($excluded);
|
||||||
|
|
||||||
// Always include the vendor directory
|
// Always include the vendor directory
|
||||||
print_info(" ← vendor/");
|
print_info(" ← vendor/");
|
||||||
$manifest->addDirectory("vendor");
|
$manifest->addDirectory("vendor");
|
||||||
@ -130,10 +153,12 @@ class Builder
|
|||||||
$this->manifest = $manifest;
|
$this->manifest = $manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateBootstrap(\Phar $phar, $type, $index=null, array $bins=[])
|
private function generateBootstrap(\Phar $phar, $type, $index=null, ?array $bins=null)
|
||||||
{
|
{
|
||||||
print_info("Generating bootstrap stub...");
|
print_info("Generating bootstrap stub...");
|
||||||
|
|
||||||
|
$bins = (array)$bins;
|
||||||
|
|
||||||
if (!$index && count($bins)==0) {
|
if (!$index && count($bins)==0) {
|
||||||
$indexFile = '<?php require_once __DIR__."/vendor/autoload.php";';
|
$indexFile = '<?php require_once __DIR__."/vendor/autoload.php";';
|
||||||
} elseif (count($bins)>1) {
|
} elseif (count($bins)>1) {
|
||||||
@ -159,10 +184,12 @@ class Builder
|
|||||||
}
|
}
|
||||||
|
|
||||||
$stub = "#!/usr/bin/env php\n".$phar->createDefaultStub($index);
|
$stub = "#!/usr/bin/env php\n".$phar->createDefaultStub($index);
|
||||||
|
|
||||||
$phar->addFromString($index, $indexFile);
|
|
||||||
$phar->setStub($stub);
|
$phar->setStub($stub);
|
||||||
|
|
||||||
|
if ($index) {
|
||||||
|
$phar->addFromString($index, $indexFile);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function stripShebang($str)
|
private function stripShebang($str)
|
||||||
@ -201,20 +228,30 @@ class Builder
|
|||||||
|
|
||||||
print_info("Adding files...");
|
print_info("Adding files...");
|
||||||
|
|
||||||
$phar = new \Phar($this->output);
|
$tempName = uniqid("phar").".phar";
|
||||||
|
$phar = new \Phar($tempName);
|
||||||
|
|
||||||
$total = count($this->manifest);
|
$total = count($this->manifest);
|
||||||
$pcf = 100 / $total;
|
$pcf = 100 / $total;
|
||||||
$bw = 40;
|
$bw = 40;
|
||||||
$pbf = $bw / $total;
|
$tw = intval(exec("tput cols"));
|
||||||
|
$pbf = $tw / $total;
|
||||||
$index = 0;
|
$index = 0;
|
||||||
|
$spinner = [ "/", "-", "\\", "|" ];
|
||||||
|
$s = 0; $t = microtime(true);
|
||||||
|
$totalBytes = 0;
|
||||||
foreach ($this->manifest as $object) {
|
foreach ($this->manifest as $object) {
|
||||||
// printf(" %s: %s\n", $object->getFilename(), $object->getLocalName());
|
// printf(" %s: %s\n", $object->getFilename(), $object->getLocalName());
|
||||||
$object->addToPhar($phar);
|
$object->addToPhar($phar);
|
||||||
if (posix_isatty(STDOUT) && ($index++ % 25 == 0)) {
|
$index++;
|
||||||
|
$totalBytes += $object->getFilesize();
|
||||||
|
if (posix_isatty(STDOUT) && (microtime(true)>$t+.2)) {
|
||||||
|
$t = microtime(true);
|
||||||
$pc = $pcf * $index;
|
$pc = $pcf * $index;
|
||||||
$pb = round($pbf * $index);
|
$pb = round($pbf * $index);
|
||||||
printf("\r[%s%s] %.1f%%", str_repeat("=",$pb), str_repeat(" ",$bw-$pb), $pc);
|
$bar = str_pad(sprintf(" %4.1f%% %d files, %.1fKiB %s ", $pc, $index, $totalBytes/1024, dirname($object->getFilename())), $tw);
|
||||||
|
echo "\r\e[30;42m".substr($bar, 0, $pb)."\e[0m".substr($bar, $pb);
|
||||||
|
//printf("\r%4.1f%% [%s%s%s] %d files, %.1fKiB", $pc, str_repeat("=",$pb), $spinner[$s=(($s+1)%4)], str_repeat(" ",$bw-$pb), $index, $totalBytes/1024);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (posix_isatty(STDOUT)) {
|
if (posix_isatty(STDOUT)) {
|
||||||
@ -226,8 +263,62 @@ class Builder
|
|||||||
$this->generateBootstrap($phar, $this->pharType, $this->index, $this->bins);
|
$this->generateBootstrap($phar, $this->pharType, $this->index, $this->bins);
|
||||||
$this->writeMetadata($phar, (array)(array_key_exists('metadata',$this->pharOpts)?$this->pharOpts['metadata']:[]));
|
$this->writeMetadata($phar, (array)(array_key_exists('metadata',$this->pharOpts)?$this->pharOpts['metadata']:[]));
|
||||||
|
|
||||||
|
if (file_exists($this->output)) {
|
||||||
|
unlink($this->output);
|
||||||
|
}
|
||||||
|
rename($tempName, $this->output);
|
||||||
chmod($this->output, 0777);
|
chmod($this->output, 0777);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function initConfig()
|
||||||
|
{
|
||||||
|
print_info("Configuring pharlite");
|
||||||
|
|
||||||
|
$askString = function($prompt, $default=null) {
|
||||||
|
return readline($prompt." [".$default."]? ")?:null;
|
||||||
|
};
|
||||||
|
|
||||||
|
$composer = json_decode(file_get_contents($this->path."/composer.json"));
|
||||||
|
|
||||||
|
if (!isset($composer->extra)) {
|
||||||
|
$composer->extra = (object)[];
|
||||||
|
}
|
||||||
|
if (!isset($composer->extra->phar)) {
|
||||||
|
$composer->extra->phar = (object)[];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($output = $askString('Output filename', @$composer->extra->phar->output)) {
|
||||||
|
$composer->extra->phar->output = $output;
|
||||||
|
}
|
||||||
|
if ($index = $askString('Index file (for web phar)', @$composer->extra->phar->index)) {
|
||||||
|
$composer->extra->phar->index = $index;
|
||||||
|
}
|
||||||
|
if ($stub = $askString('Loader stub', @$composer->extra->phar->stub)) {
|
||||||
|
$composer->extra->phar->stub = $stub;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($composer->bin)) {
|
||||||
|
print_warn("You have no bins defined in your composer.json. Specify at least one bin to create an application phar.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($this->path."/composer.bak")) {
|
||||||
|
unlink($this->path."/composer.bak");
|
||||||
|
}
|
||||||
|
rename($this->path."/composer.json", $this->path."/composer.bak");
|
||||||
|
file_put_contents($this->path."/composer.json", json_encode($composer, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)."\n");
|
||||||
|
|
||||||
|
exec("composer validate --no-check-lock -q", $output, $retval);
|
||||||
|
if ($retval == 0) {
|
||||||
|
print_info("Updated composer.json");
|
||||||
|
unlink($this->path."/composer.bak");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error("The composer.json file isn't valid after being modified. Reverting...");
|
||||||
|
unlink($this->path."/composer.json");
|
||||||
|
rename($this->path."/composer.bak", $this->path."/composer.json");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,18 @@ class Manifest implements \IteratorAggregate, \Countable
|
|||||||
/** @var ManifestObject[] The included objects */
|
/** @var ManifestObject[] The included objects */
|
||||||
protected $objects = [];
|
protected $objects = [];
|
||||||
|
|
||||||
|
protected $excluded = [];
|
||||||
|
|
||||||
public function __construct($root)
|
public function __construct($root)
|
||||||
{
|
{
|
||||||
$this->root = $root;
|
$this->root = $root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setExcluded(array $patterns=[])
|
||||||
|
{
|
||||||
|
$this->excluded = $patterns;
|
||||||
|
}
|
||||||
|
|
||||||
public function addDirectory($path, callable $filter=null)
|
public function addDirectory($path, callable $filter=null)
|
||||||
{
|
{
|
||||||
$path = rtrim($path, DIRECTORY_SEPARATOR);
|
$path = rtrim($path, DIRECTORY_SEPARATOR);
|
||||||
@ -32,11 +39,19 @@ class Manifest implements \IteratorAggregate, \Countable
|
|||||||
|
|
||||||
public function addFile($file)
|
public function addFile($file)
|
||||||
{
|
{
|
||||||
|
// Don't add the file if it matches an excluded pattern
|
||||||
|
if ($this->excluded) foreach ($this->excluded as $p) {
|
||||||
|
if (fnmatch($p, $file)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out local path name
|
||||||
if (strpos($file, $this->root) === 0) {
|
if (strpos($file, $this->root) === 0) {
|
||||||
$local = substr($file, 0, strlen($this->root));
|
$local = substr($file, 0, strlen($this->root));
|
||||||
} else {
|
} else {
|
||||||
$local = $file;
|
$local = $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add object to manifest
|
||||||
$this->objects[] = new ManifestObject($file, $local);
|
$this->objects[] = new ManifestObject($file, $local);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,29 +13,45 @@ class ManifestObject
|
|||||||
|
|
||||||
protected $localname;
|
protected $localname;
|
||||||
|
|
||||||
|
protected $stripped = false;
|
||||||
|
|
||||||
public function __construct($filename, $localname=null)
|
public function __construct($filename, $localname=null)
|
||||||
{
|
{
|
||||||
$this->filename = $filename;
|
$this->filename = $filename;
|
||||||
$this->localname = $localname;
|
$this->localname = $localname;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFilename()
|
public function setStripped(bool $stripped)
|
||||||
|
{
|
||||||
|
$this->stripped = $stripped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStripped():bool
|
||||||
|
{
|
||||||
|
return $this->stripped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilename():string
|
||||||
{
|
{
|
||||||
return $this->filename;
|
return $this->filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLocalName()
|
public function getLocalName():string
|
||||||
{
|
{
|
||||||
return $this->localname;
|
return $this->localname;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addToPhar(\Phar $phar)
|
public function addToPhar(\Phar $phar)
|
||||||
{
|
{
|
||||||
|
if ($this->stripped) {
|
||||||
|
// strip and add
|
||||||
|
} else {
|
||||||
$phar->addFile(
|
$phar->addFile(
|
||||||
$this->getFilename(),
|
$this->getFilename(),
|
||||||
$this->getLocalName()
|
$this->getLocalName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function addFiltered(\Phar $phar, callable $filter)
|
public function addFiltered(\Phar $phar, callable $filter)
|
||||||
{
|
{
|
||||||
@ -43,4 +59,9 @@ class ManifestObject
|
|||||||
$body = call_user_func($filter, $body);
|
$body = call_user_func($filter, $body);
|
||||||
$phar->addFromString($this->getLocalName(), $body);
|
$phar->addFromString($this->getLocalName(), $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFilesize()
|
||||||
|
{
|
||||||
|
return filesize($this->filename);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user