From 2413b55c60e42adee0b40014590fbe3f58145663 Mon Sep 17 00:00:00 2001 From: Hector Prats Date: Wed, 14 Mar 2018 17:38:12 +0100 Subject: [PATCH] LocalChanges for ArchiveFiles --- src/Composer/Command/StatusCommand.php | 16 ++- src/Composer/Downloader/ArchiveDownloader.php | 6 +- .../Downloader/DownloaderInterface.php | 9 ++ src/Composer/Downloader/FileDownloader.php | 26 +++- src/Composer/Package/Comparer/Comparer.php | 128 ++++++++++++++++++ 5 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 src/Composer/Package/Comparer/Comparer.php diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php index e45d7b7c7..02dbf1b6b 100644 --- a/src/Composer/Command/StatusCommand.php +++ b/src/Composer/Command/StatusCommand.php @@ -12,6 +12,7 @@ namespace Composer\Command; +use Composer\Downloader\DownloaderInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -44,7 +45,8 @@ class StatusCommand extends BaseCommand ->setDefinition(array( new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Show modified files for each directory that contains changes.'), )) - ->setHelp(<<setHelp( + <<getLocalChanges($package, $targetDir)) { $errors[$targetDir] = $changes; } - } - - if ($downloader instanceof VcsCapableDownloaderInterface) { + } elseif ($downloader instanceof VcsCapableDownloaderInterface) { if ($currentRef = $downloader->getVcsReference($package, $targetDir)) { switch ($package->getInstallationSource()) { case 'source': @@ -121,12 +121,14 @@ EOT ); } } - } - - if ($downloader instanceof DvcsDownloaderInterface) { + } elseif ($downloader instanceof DvcsDownloaderInterface) { if ($unpushed = $downloader->getUnpushedChanges($package, $targetDir)) { $unpushedChanges[$targetDir] = $unpushed; } + } elseif ($downloader instanceof DownloaderInterface) { + if ($changes = $downloader->getLocalChanges($package, $targetDir)) { + $errors[$targetDir] = $changes; + } } } diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index 24256c81f..d041a7f88 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -27,6 +27,8 @@ abstract class ArchiveDownloader extends FileDownloader { /** * {@inheritDoc} + * @throws \RuntimeException + * @throws \UnexpectedValueException */ public function download(PackageInterface $package, $path, $output = true) { @@ -35,7 +37,9 @@ abstract class ArchiveDownloader extends FileDownloader while ($retries--) { $fileName = parent::download($package, $path, $output); - $this->io->writeError(' Extracting archive', false, IOInterface::VERBOSE); + if ($output) { + $this->io->writeError(' Extracting archive', false, IOInterface::VERBOSE); + } try { $this->filesystem->ensureDirectoryExists($temporaryDir); diff --git a/src/Composer/Downloader/DownloaderInterface.php b/src/Composer/Downloader/DownloaderInterface.php index 713bf36dc..d3ed12cdf 100644 --- a/src/Composer/Downloader/DownloaderInterface.php +++ b/src/Composer/Downloader/DownloaderInterface.php @@ -61,4 +61,13 @@ interface DownloaderInterface * @return DownloaderInterface */ public function setOutputProgress($outputProgress); + + /** + * Checks for changes to the local copy + * + * @param PackageInterface $package package instance + * @param string $path package directory + * @return string|null changes or null + */ + public function getLocalChanges(PackageInterface $package, $path); } diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 0cc531704..7655aabe3 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -16,6 +16,7 @@ use Composer\Config; use Composer\Cache; use Composer\Factory; use Composer\IO\IOInterface; +use Composer\Package\Comparer\Comparer; use Composer\Package\PackageInterface; use Composer\Plugin\PluginEvents; use Composer\Plugin\PreFileDownloadEvent; @@ -166,7 +167,9 @@ class FileDownloader implements DownloaderInterface $this->cache->copyFrom($cacheKey, $fileName); } } else { - $this->io->writeError('Loading from cache', false); + if (!$this->outputProgress) { + $this->io->writeError('Loading from cache', false); + } } if (!file_exists($fileName)) { @@ -278,4 +281,25 @@ class FileDownloader implements DownloaderInterface return $package->getName().'/'.$cacheKey.'.'.$package->getDistType(); } + + /** + * {@inheritDoc} + * @throws \RuntimeException + */ + public function getLocalChanges(PackageInterface $package, $targetDir) + { + if ($this->outputProgress) { + $this->io->writeError(' - Installing Original ' . $package->getName() . ' (' . $package->getFullPrettyVersion() . ') and Checking: ', true); + } + $this->download($package, $targetDir.'_compare', false); + + $comparer = new Comparer(); + $comparer->setSource($targetDir.'_compare'); + $comparer->setUpdate($targetDir); + $comparer->doCompare(); + $output = $comparer->getChanged(true, true); + $this->filesystem->removeDirectory($targetDir.'_compare'); + + return trim($output); + } } diff --git a/src/Composer/Package/Comparer/Comparer.php b/src/Composer/Package/Comparer/Comparer.php new file mode 100644 index 000000000..ed1931e82 --- /dev/null +++ b/src/Composer/Package/Comparer/Comparer.php @@ -0,0 +1,128 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Package\Comparer; + +/** + * class Comparer + * + * @author Hector Prats + */ +class Comparer +{ + private $source; + private $update; + private $changed; + + public function setSource($source) + { + $this->source = $source; + } + + public function setUpdate($update) + { + $this->update = $update; + } + + public function getChanged($toString = false, $explicated = false) + { + $changed = $this->changed; + if (!count($changed)) { + return false; + } + if ($explicated) { + foreach ($changed as $sectionKey => $itemSection) { + foreach ($itemSection as $itemKey => $item) { + $changed[$sectionKey][$itemKey] = $item.' ('.$sectionKey.')'; + } + } + } + + if ($toString) { + foreach ($changed as $sectionKey => $itemSection) { + foreach ($itemSection as $itemKey => $item) { + $changed['string'][] = $item."\r\n"; + } + } + $changed = implode("\r\n", $changed['string']); + } + + return $changed; + } + + public function doCompare() + { + $source = array(); + $destination = array(); + $this->changed = array(); + $currentDirectory = getcwd(); + chdir($this->source); + $source = $this->doTree('.', $source); + if (!is_array($source)) { + return; + } + chdir($this->update); + $destination = $this->doTree('.', $destination); + if (!is_array($destination)) { + exit; + } + chdir($currentDirectory); + foreach ($source as $dir => $value) { + foreach ($value as $file => $hash) { + if (isset($destination[$dir][$file])) { + if ($hash !== $destination[$dir][$file]) { + $this->changed['changed'][] = $dir.'/'.$file; + } + } else { + $this->changed['removed'][] = $dir.'/'.$file; + } + } + } + foreach ($destination as $dir => $value) { + foreach ($value as $file => $hash) { + if (!isset($source[$dir][$file])) { + $this->changed['added'][] = $dir.'/'.$file; + } + } + } + } + + private function doTree($dir, &$array) + { + if ($dh = opendir($dir)) { + while ($file = readdir($dh)) { + if ($file !== '.' && $file !== '..') { + if (is_dir($dir.'/'.$file)) { + if (!count($array)) { + $array[0] = 'Temp'; + } + if (!$this->doTree($dir.'/'.$file, $array)) { + return false; + } + } else { + if (filesize($dir.'/'.$file)) { + set_time_limit(30); + $array[$dir][$file] = md5_file($dir.'/'.$file); + } + } + } + } + if (count($array) > 1 && isset($array['0'])) { + unset($array['0']); + } + + return $array; + } + + return false; + } +}