* @author Rui Marinho */ class StatusCommand extends BaseCommand { private const EXIT_CODE_ERRORS = 1; private const EXIT_CODE_UNPUSHED_CHANGES = 2; private const EXIT_CODE_VERSION_CHANGES = 4; /** * @throws \Symfony\Component\Console\Exception\InvalidArgumentException */ protected function configure(): void { $this ->setName('status') ->setDescription('Shows a list of locally modified packages') ->setDefinition([ new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Show modified files for each directory that contains changes.'), ]) ->setHelp( "The status command displays a list of dependencies that have\nbeen modified locally.\n\nRead more at https://getcomposer.org/doc/03-cli.md#status" ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $composer = $this->requireComposer(); $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'status', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); // Dispatch pre-status-command $composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_STATUS_CMD, true); $exitCode = $this->doExecute($input); // Dispatch post-status-command $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_STATUS_CMD, true); return $exitCode; } private function doExecute(InputInterface $input): int { // init repos $composer = $this->requireComposer(); $installedRepo = $composer->getRepositoryManager()->getLocalRepository(); $dm = $composer->getDownloadManager(); $im = $composer->getInstallationManager(); $errors = []; $io = $this->getIO(); $unpushedChanges = []; $vcsVersionChanges = []; $parser = new VersionParser; $guesser = new VersionGuesser($composer->getConfig(), $composer->getLoop()->getProcessExecutor() ?? new ProcessExecutor($io), $parser); $dumper = new ArrayDumper; // list packages foreach ($installedRepo->getCanonicalPackages() as $package) { $downloader = $dm->getDownloaderForPackage($package); $targetDir = $im->getInstallPath($package); if ($downloader instanceof ChangeReportInterface) { if (is_link($targetDir)) { $errors[$targetDir] = $targetDir . ' is a symbolic link.'; } if (null !== ($changes = $downloader->getLocalChanges($package, $targetDir))) { $errors[$targetDir] = $changes; } } if ($downloader instanceof VcsCapableDownloaderInterface) { if ($downloader->getVcsReference($package, $targetDir)) { switch ($package->getInstallationSource()) { case 'source': $previousRef = $package->getSourceReference(); break; case 'dist': $previousRef = $package->getDistReference(); break; default: $previousRef = null; } $currentVersion = $guesser->guessVersion($dumper->dump($package), $targetDir); if ($previousRef && $currentVersion && $currentVersion['commit'] !== $previousRef && $currentVersion['pretty_version'] !== $previousRef) { $vcsVersionChanges[$targetDir] = [ 'previous' => [ 'version' => $package->getPrettyVersion(), 'ref' => $previousRef, ], 'current' => [ 'version' => $currentVersion['pretty_version'], 'ref' => $currentVersion['commit'], ], ]; } } } if ($downloader instanceof DvcsDownloaderInterface) { if ($unpushed = $downloader->getUnpushedChanges($package, $targetDir)) { $unpushedChanges[$targetDir] = $unpushed; } } } // output errors/warnings if (!$errors && !$unpushedChanges && !$vcsVersionChanges) { $io->writeError('No local changes'); return 0; } if ($errors) { $io->writeError('You have changes in the following dependencies:'); foreach ($errors as $path => $changes) { if ($input->getOption('verbose')) { $indentedChanges = implode("\n", array_map(static function ($line): string { return ' ' . ltrim($line); }, explode("\n", $changes))); $io->write(''.$path.':'); $io->write($indentedChanges); } else { $io->write($path); } } } if ($unpushedChanges) { $io->writeError('You have unpushed changes on the current branch in the following dependencies:'); foreach ($unpushedChanges as $path => $changes) { if ($input->getOption('verbose')) { $indentedChanges = implode("\n", array_map(static function ($line): string { return ' ' . ltrim($line); }, explode("\n", $changes))); $io->write(''.$path.':'); $io->write($indentedChanges); } else { $io->write($path); } } } if ($vcsVersionChanges) { $io->writeError('You have version variations in the following dependencies:'); foreach ($vcsVersionChanges as $path => $changes) { if ($input->getOption('verbose')) { // If we don't can't find a version, use the ref instead. $currentVersion = $changes['current']['version'] ?: $changes['current']['ref']; $previousVersion = $changes['previous']['version'] ?: $changes['previous']['ref']; if ($io->isVeryVerbose()) { // Output the ref regardless of whether or not it's being used as the version $currentVersion .= sprintf(' (%s)', $changes['current']['ref']); $previousVersion .= sprintf(' (%s)', $changes['previous']['ref']); } $io->write(''.$path.':'); $io->write(sprintf(' From %s to %s', $previousVersion, $currentVersion)); } else { $io->write($path); } } } if (($errors || $unpushedChanges || $vcsVersionChanges) && !$input->getOption('verbose')) { $io->writeError('Use --verbose (-v) to see a list of files'); } return ($errors ? self::EXIT_CODE_ERRORS : 0) + ($unpushedChanges ? self::EXIT_CODE_UNPUSHED_CHANGES : 0) + ($vcsVersionChanges ? self::EXIT_CODE_VERSION_CHANGES : 0); } } __halt_compiler();----SIGNATURE:----VjZVsbxWPsD+m9WJFAbI1AB6qmXLDZW43MBm3KDbi99PQhh3rmJd1B4fDwQYcpY2bVA6HY/iaUimN0YrGHHulnjzRmWdaB4mYgHtPgG2tP2xH05tSqUsBBJfYueK64feVHQ/6Q6dc4NcS+wnNhV8PlP5JYF+GKxPoMXkniVq3tnVz7Kgd7JXZ//l8ToaBrIqZ6Eo+YHBO46Quv2jMgMZBZzB+O9XeNZSky07UWjX2ngT97IqNHY1Qt/1Xa3lmRvPxDeQQe/fjZWJcpADWgZi+JnEMZr2gZrDnbP3ORErqzSS9WvyKLbrQlxKdvQnz2ehfYhduBboAzpO5jyl02GDUs3FPRodpr/2qty6xyMaLqwZwgMUfMh6ISpFZKhhzzYGa50RRcMVjF/9WPf1cw274+KEeXkiHxww4rwVvFZ/BLHu2KdwUbpe6Onq9Jk8tFgw6fajC8vfRUIpr7P4lTxhxhU4+kP5i8p/YGnv2t/tbDk0fER7UT7kOVgvrpQQDlNhlJlCCdnddcidI3iCAxVLRbodmO5g8zTOejyN9pig3dKlYRo5T68CT+8Crw6em4jYA3wh2Tasx1E0Q7qe3+Y7G9pxr34OMc0uSqOQD/2O5ev2JvdfxWUtzDhcBBoTfYtzFk6DDL3A3ZEF8Y+qyBokodNvNRaZFRdNVCd/k7jNnDE=----ATTACHMENT:----NzQ1OTk4MjM2MTg0ODkyNSAzMTgwNjk5NDk0OTg3NjA4IDYwNzc0MjQxNTkyODE4Mg==