diff --git a/build-phar.php b/build-phar.php new file mode 100644 index 000000000..68c4dd8c5 --- /dev/null +++ b/build-phar.php @@ -0,0 +1,10 @@ +addFile('composer.json'); +$phar->addFile('composer.lock'); +$phar->compressFiles(Phar::BZ2); + +$x = new PharFileInfo('phar://demo.phar/composer.lock'); +$x->compress(Phar::GZ); diff --git a/src/Console/Command/Diff.php b/src/Console/Command/Diff.php index a77a21f0d..2229e53f2 100644 --- a/src/Console/Command/Diff.php +++ b/src/Console/Command/Diff.php @@ -29,6 +29,8 @@ use Throwable; use Webmozart\Assert\Assert; use function array_map; +use function array_search; +use function array_sum; use function count; // TODO: migrate to Safe API use function is_string; @@ -122,10 +124,13 @@ public function execute(IO $io): int return ExitCode::FAILURE; } - $result1 = $this->compareArchives($diff, $io); - $result2 = $this->compareContents($diff, $io); + $results = [ + $this->compareCheckSums($diff, $io), + $this->compareArchives($diff, $io), + $this->compareContents($diff, $io), + ]; - return $result1 + $result2; + return array_sum($results); } /** @@ -146,6 +151,37 @@ private static function getPaths(IO $io): array ); } + private function compareCheckSums(PharDiff $diff, IO $io): int + { + $io->comment('Comparing the two archives... (do not check the signatures)'); + + $pharInfoA = $diff->getPharA()->getPharInfo(); + $pharInfoB = $diff->getPharB()->getPharInfo(); + + if ($pharInfoA->equals($pharInfoB)) { + $io->success('The two archives are identical'); + + return ExitCode::SUCCESS; + } + + self::renderArchive( + $diff->getPharA()->getFileName(), + $pharInfoA, + $io, + ); + + $io->newLine(); + + self::renderArchive( + $diff->getPharB()->getFileName(), + $pharInfoB, + $io, + ); + + return ExitCode::FAILURE; + } + + private function compareArchives(PharDiff $diff, IO $io): int { $io->comment('Comparing the two archives... (do not check the signatures)'); diff --git a/src/Pharaoh/Pharaoh.php b/src/Pharaoh/Pharaoh.php index bc3c2e191..3a12f8e38 100644 --- a/src/Pharaoh/Pharaoh.php +++ b/src/Pharaoh/Pharaoh.php @@ -51,6 +51,7 @@ use function file_exists; use function file_put_contents; use function KevinGH\Box\FileSystem\copy; +use function KevinGH\Box\FileSystem\dump_file; use function KevinGH\Box\FileSystem\mkdir; use function KevinGH\Box\FileSystem\remove; use function KevinGH\Box\FileSystem\tempnam; @@ -58,55 +59,33 @@ use function sys_get_temp_dir; use const DIRECTORY_SEPARATOR; +/** + * Pharaoh is a wrapper around Phar + */ final class Pharaoh { - public Phar $phar; - - public string $tmp; - - public static string $stubfile; + private static string $stubfile; + private Phar $phar; + private string $tmp; private string $fileName; private ?PharInfo $pharInfo = null; private ?string $path = null; - public function __construct(string $file, ?string $alias = null) + public function __construct(string $file) { Assert::readable($file); - Assert::true( + Assert::false( PharPhpSettings::isReadonly(), 'Pharaoh cannot be used if phar.readonly is enabled in php.ini', ); - // Set the static variable here - if (!isset(self::$stubfile)) { - self::$stubfile = Hex::encode(random_bytes(12)).'.pharstub'; - } - - // We have to give every one a different alias, or it pukes. - $alias ??= (Hex::encode(random_bytes(16)).'.phar'); - - $tmpFile = sys_get_temp_dir().DIRECTORY_SEPARATOR.$alias; - copy($file, $tmpFile); - - $phar = new Phar($tmpFile); - $phar->setAlias($alias); - - // Make a random folder in /tmp - /** @var string|bool $tmp */ - $tmp = tempnam(sys_get_temp_dir(), 'phr_'); + self::initStubFileName(); - Assert::false(file_exists($tmp)); - mkdir($tmp, 0o755); - - // Let's extract to our temporary directory - $phar->extractTo($tmp); + $tmp = self::createTmpDir(); + $phar = self::createTmpPhar($file); - // Also extract the stub - file_put_contents( - $tmp.'/'.self::$stubfile, - $phar->getStub() - ); + self::extractPhar($phar, $tmp); $this->tmp = $tmp; $this->phar = $phar; @@ -139,4 +118,48 @@ public function getPharInfo(): PharInfo return $this->pharInfo; } + + private static function initStubFileName(): void + { + if (!isset(self::$stubfile)) { + self::$stubfile = Hex::encode(random_bytes(12)).'.pharstub'; + } + } + + private static function createTmpPhar(string $file): Phar + { + // We have to give every one a different alias, or it pukes. + $alias = Hex::encode(random_bytes(16)).'.phar'; + + $tmpFile = sys_get_temp_dir().DIRECTORY_SEPARATOR.$alias; + copy($file, $tmpFile); + + $phar = new Phar($tmpFile); + $phar->setAlias($alias); + + return $phar; + } + + private static function createTmpDir(): string + { + $tmp = tempnam(sys_get_temp_dir(), 'box_'); + + remove($tmp); + mkdir($tmp, 0o755); + + return $tmp; + } + + private static function extractPhar(Phar $phar, string $tmp): void + { + // Extract the PHAR content + $phar->extractTo($tmp); + + // Extract the stub; Phar::extractTo() does not do it since it + // is internal to the PHAR. + dump_file( + $tmp.DIRECTORY_SEPARATOR.self::$stubfile, + $phar->getStub(), + ); + } }