Skip to content

Commit

Permalink
refactor: Move the different diff methods into dedicated classes (#1058)
Browse files Browse the repository at this point in the history
  • Loading branch information
theofidry authored Oct 11, 2023
1 parent df76b1f commit e5ec207
Show file tree
Hide file tree
Showing 7 changed files with 424 additions and 289 deletions.
71 changes: 1 addition & 70 deletions src/Console/Command/Diff.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,8 @@
use Symfony\Component\Filesystem\Path;
use Webmozart\Assert\Assert;
use function array_map;
use function count;
use function explode;
use function implode;
use function is_string;
use function sprintf;
use const PHP_EOL;

/**
* @private
Expand Down Expand Up @@ -272,72 +268,7 @@ private function renderContentsDiff(PharDiff $diff, DiffMode $diffMode, string $
),
);

$diffResult = $diff->diff($diffMode, $checksumAlgorithm);

if (null === $diffResult || [[], []] === $diffResult) {
$io->writeln('No difference could be observed with this mode.');

return;
}

if (is_string($diffResult)) {
// Git or GNU diff: we don't have much control on the format
$io->writeln($diffResult);

return;
}

$io->writeln(sprintf(
'--- Files present in "%s" but not in "%s"',
$diff->getPharInfoA()->getFileName(),
$diff->getPharInfoB()->getFileName(),
));
$io->writeln(sprintf(
'+++ Files present in "%s" but not in "%s"',
$diff->getPharInfoB()->getFileName(),
$diff->getPharInfoA()->getFileName(),
));

$io->newLine();

self::renderPaths('-', $diff->getPharInfoA(), $diffResult[0], $io);
self::renderPaths('+', $diff->getPharInfoB(), $diffResult[1], $io);

$io->error(
sprintf(
'%d file(s) difference',
count($diffResult[0]) + count($diffResult[1]),
),
);
}

/**
* @param list<non-empty-string> $paths
*/
private static function renderPaths(string $symbol, PharInfo $pharInfo, array $paths, IO $io): void
{
$bufferedOutput = new BufferedOutput(
$io->getVerbosity(),
$io->isDecorated(),
$io->getOutput()->getFormatter(),
);

PharInfoRenderer::renderContent(
$bufferedOutput,
$pharInfo,
false,
false,
);

$lines = array_map(
static fn (string $line) => '' === $line ? '' : $symbol.' '.$line,
explode(
PHP_EOL,
$bufferedOutput->fetch(),
),
);

$io->writeln($lines);
$diff->diff($diffMode, $checksumAlgorithm, $io);
}

private static function renderSummary(PharInfo $pharInfo, IO $io): void
Expand Down
130 changes: 130 additions & 0 deletions src/Phar/Differ/ChecksumDiffer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Phar\Differ;

use Fidry\Console\Input\IO;
use KevinGH\Box\Phar\PharInfo;
use UnexpectedValueException;
use ValueError;
use function implode;

final class ChecksumDiffer implements Differ
{
public function __construct(
private string $checksumAlgorithm,
) {
}

public function diff(
PharInfo $pharInfoA,
PharInfo $pharInfoB,
IO $io,
): void {
$diff = self::computeDiff(
$pharInfoA,
$pharInfoB,
$this->checksumAlgorithm,
);

$io->writeln($diff ?? Differ::NO_DIFF_MESSAGE);
}

private static function computeDiff(
PharInfo $pharInfoA,
PharInfo $pharInfoB,
string $checksumAlgorithm,
): ?string {
$pharInfoAFileHashes = self::getFileHashesByRelativePathname(
$pharInfoA,
$checksumAlgorithm,
);
$pharInfoBFileHashes = self::getFileHashesByRelativePathname(
$pharInfoB,
$checksumAlgorithm,
);
$output = [
'<diff-expected>--- PHAR A</diff-expected>',
'<diff-actual>+++ PHAR B</diff-actual>',
'@@ @@',
];

foreach ($pharInfoAFileHashes as $filePath => $fileAHash) {
if (!array_key_exists($filePath, $pharInfoBFileHashes)) {
$output[] = $filePath;
$output[] = sprintf(
"\t<diff-expected>- %s</diff-expected>",
$fileAHash,
);

continue;
}

$fileBHash = $pharInfoBFileHashes[$filePath];
unset($pharInfoBFileHashes[$filePath]);

if ($fileAHash === $fileBHash) {
continue;
}

$output[] = $filePath;
$output[] = sprintf(
"\t<diff-expected>- %s</diff-expected>",
$fileAHash,
);
$output[] = sprintf(
"\t<diff-actual>+ %s</diff-actual>",
$fileBHash,
);
}

foreach ($pharInfoBFileHashes as $filePath => $fileBHash) {
$output[] = $filePath;
$output[] = sprintf(
"\t<diff-actual>+ %s</diff-actual>",
$fileBHash,
);
}

return 3 === count($output) ? null : implode("\n", $output);
}

/**
* @return array<string, string>
*/
private static function getFileHashesByRelativePathname(
PharInfo $pharInfo,
string $algorithm,
): array {
$hashFiles = [];

try {
foreach ($pharInfo->getFiles() as $file) {
$hashFiles[$file->getRelativePathname()] = hash_file(
$algorithm,
$file->getPathname(),
);
}
} catch (ValueError) {
throw new UnexpectedValueException(
sprintf(
'Unexpected algorithm "%s". Please pick a registered hashing algorithm (checksum `hash_algos()`).',
$algorithm,
),
);
}

return $hashFiles;
}
}
29 changes: 29 additions & 0 deletions src/Phar/Differ/Differ.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Phar\Differ;

use Fidry\Console\Input\IO;
use KevinGH\Box\Phar\PharInfo;

interface Differ
{
public const NO_DIFF_MESSAGE = 'No difference could be observed with this mode.';

public function diff(
PharInfo $pharInfoA,
PharInfo $pharInfoB,
IO $io,
): void;
}
33 changes: 33 additions & 0 deletions src/Phar/Differ/DifferFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Phar\Differ;

use KevinGH\Box\Console\Command\Extract;
use KevinGH\Box\Phar\DiffMode;

final class DifferFactory
{
public function create(
DiffMode $mode,
string $checksumAlgorithm,
): Differ {
return match ($mode) {
DiffMode::FILE_NAME => new FilenameDiffer(),
DiffMode::GIT => new ProcessCommandBasedDiffer('git diff --no-index'),
DiffMode::GNU => new ProcessCommandBasedDiffer('diff --exclude='.Extract::PHAR_META_PATH),
DiffMode::CHECKSUM => new ChecksumDiffer($checksumAlgorithm),
};
}
}
Loading

0 comments on commit e5ec207

Please sign in to comment.