Skip to content

Commit

Permalink
feat(command): improving command options parsing.
Browse files Browse the repository at this point in the history
  • Loading branch information
razshare committed Dec 17, 2024
1 parent 42fd920 commit 11e5c7e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 39 deletions.
16 changes: 6 additions & 10 deletions src/commands/Core/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,25 @@ public function __construct(private EnvironmentInterface $environment) {

public function build(CommandBuilder $builder):void {
$builder->required('b', 'build');
$builder->required('e', 'environment');
$builder->optional('e', 'environment');
$builder->optional('o', 'optimize');
}

public function run(CommandContext $context):Result {
$environmentFile = $context->get('e');
$environment = asFileName($context->get('environment')?:'build.ini')->absolute();

if (!$environmentFile) {
return error("Please point to an environment file using the `--environment` or `-e` options.\n");
if (!File::exists($environment)) {
return error("File `$environment` doesn't seem to exist.");
}

if (!File::exists(asFileName($environmentFile))) {
return error("File `$environmentFile` doesn't seem to exist.");
}

$this->environment->withFileName($environmentFile);
$this->environment->withFileName($environment);
$this->environment->load()->unwrap($error);
if ($error) {
return error($error);
}

$optimize = (bool)$context->get('optimize');

build($optimize)->unwrap($error);
if ($error) {
return error($error);
Expand Down
73 changes: 46 additions & 27 deletions src/lib/Core/FileName.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,28 @@
use Phar;
use Stringable;

/**
* A `FileName` is an object that will stringify itself
* into `$path` when cast to `string`.\
* The unique feature of `FileName` is that it will
* automatically detect if `$path`
* is included in the current `.phar` bundle and it
* will return the correct string according to `.phar` semantics.
* @package CatPaw\Core
*/
class FileName implements Stringable {
/**
* Create a file name starting from a `$base` directory.
* @param array<string> $base
* @return FileName
*/
public static function create(array $base):self {
return new self($base);
}

private bool $usingPhar = true;

/**
* @param array<string> $path
*/
private function __construct(private array $path) {
public function __construct(private array $path) {
}

/**
* Given a `$path`, create a file name.
* @param array<string> $path
* @return string
*/
private static function asFileName(array $path):string {
private static function glue(array $path):string {
$parts = [];
$count = count($path);
for ($index = 0; $index < $count; $index++) {
Expand All @@ -41,7 +39,7 @@ private static function asFileName(array $path):string {
return join($parts)?:'';
}

private static function absolutePath(string $path):string {
private static function normalize(string $path):string {
$root = match (true) {
str_starts_with($path, './') => './',
str_starts_with($path, '../') => '../',
Expand All @@ -53,51 +51,72 @@ private static function absolutePath(string $path):string {
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), function($item) {
return (bool)strlen($item);
});
$absolutes = [];
$normalized = [];
foreach ($parts as $part) {
if ('.' == $part) {
continue;
}
if ('..' == $part) {
array_pop($absolutes);
array_pop($normalized);
} else {
$absolutes[] = $part;
$normalized[] = $part;
}
}
return $root.implode(DIRECTORY_SEPARATOR, $absolutes);
return $root.implode(DIRECTORY_SEPARATOR, $normalized);
}

private bool $scanPhar = true;

/**
* Ignore files and directories bundled into the `.phar` bundle when invoked from within a `.phar` bundle.\
* This makes it so that the resulting file name is always relative to the host machine, instead of it being relative to the `.phar` bundle.
* Don't scan the `.phar` bundle,
* just stringify to the original `$path`.
* @return self
*/
public function withoutPhar():self {
$this->usingPhar = false;
$this->scanPhar = false;
return $this;
}

private bool $absolute = false;

/**
* Convert to absolute file name.
* @return FileName
*/
public function absolute():self {
$this->absolute = true;
return $this;
}

private false|string $cache = false;

public function __toString():string {
if (false !== $this->cache) {
return $this->cache;
}

if (isPhar()) {
$phar = Phar::running();
$fileName = self::asFileName($this->path);
$fileName = self::glue($this->path);
$fileNamePharless = str_replace("$phar/", '', $fileName);

if ($this->usingPhar) {
if ($this->scanPhar) {
$fileNameRootless = str_replace(getcwd(), '', $fileName);
if (str_starts_with($fileNameRootless, '/')) {
$fileNameRootless = substr($fileNameRootless, 1);
}
$fileNameWithPhar = "$phar/$fileNameRootless";
if (file_exists($fileNameWithPhar)) {
return $fileNameWithPhar;
return $this->cache = $fileNameWithPhar;
}
exit();
}

return self::absolutePath($fileNamePharless);
return $this->cache = self::normalize($fileNamePharless);
} else {
return self::absolutePath(self::asFileName($this->path));
if ($this->absolute) {
return $this->cache = realpath(self::normalize(self::glue($this->path)));
}
return $this->cache = self::normalize(self::glue($this->path));
}
}
}
10 changes: 8 additions & 2 deletions src/scripts/Core/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,16 @@ function stop(string|Error $error) {
}

/**
* Given a `$path`, create a file name.
* Given a `$path`, create a `FileName`.\
* A `FileName` is an object that will stringify itself
* into `$path` when cast to `string`.\
* The unique feature of `FileName` is that it will
* automatically detect if `$path`
* is included in the current `.phar` bundle and it
* will return the correct string according to `.phar` semantics.
* @param string ...$path
* @return FileName
*/
function asFileName(string ...$path):FileName {
return FileName::create($path);
return new FileName($path);
}

0 comments on commit 11e5c7e

Please sign in to comment.