From 2413b55c60e42adee0b40014590fbe3f58145663 Mon Sep 17 00:00:00 2001 From: Hector Prats Date: Wed, 14 Mar 2018 17:38:12 +0100 Subject: [PATCH 1/3] 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; + } +} From 90ac5e0749a8b3040eb6edfa88f69b466b2ab4c9 Mon Sep 17 00:00:00 2001 From: Hector Prats Date: Fri, 16 Mar 2018 13:15:15 +0100 Subject: [PATCH 2/3] improving doc --- src/Composer/Command/StatusCommand.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php index 02dbf1b6b..d558f46fd 100644 --- a/src/Composer/Command/StatusCommand.php +++ b/src/Composer/Command/StatusCommand.php @@ -37,6 +37,9 @@ class StatusCommand extends BaseCommand const EXIT_CODE_UNPUSHED_CHANGES = 2; const EXIT_CODE_VERSION_CHANGES = 4; + /** + * @throws \Symfony\Component\Console\Exception\InvalidArgumentException + */ protected function configure() { $this @@ -55,6 +58,11 @@ EOT ; } + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int|null + */ protected function execute(InputInterface $input, OutputInterface $output) { // init repos From b1a78b60fe552bc6e7df09cb1c0154797fea6f64 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 12 Apr 2018 18:40:07 +0200 Subject: [PATCH 3/3] Remove output while the changes are being collected --- src/Composer/Downloader/FileDownloader.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 7655aabe3..e090c1b6e 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\IO\NullIO; use Composer\Package\Comparer\Comparer; use Composer\Package\PackageInterface; use Composer\Plugin\PluginEvents; @@ -288,9 +289,13 @@ class FileDownloader implements DownloaderInterface */ public function getLocalChanges(PackageInterface $package, $targetDir) { - if ($this->outputProgress) { - $this->io->writeError(' - Installing Original ' . $package->getName() . ' (' . $package->getFullPrettyVersion() . ') and Checking: ', true); - } + $prevIO = $this->io; + $prevProgress = $this->outputProgress; + + $this->io = new NullIO; + $this->io->loadConfiguration($this->config); + $this->outputProgress = false; + $this->download($package, $targetDir.'_compare', false); $comparer = new Comparer(); @@ -300,6 +305,9 @@ class FileDownloader implements DownloaderInterface $output = $comparer->getChanged(true, true); $this->filesystem->removeDirectory($targetDir.'_compare'); + $this->io = $prevIO; + $this->outputProgress = $prevProgress; + return trim($output); } }