* @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 { $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:----woJNLvuMN0nXZ4JqBDUzcuw8Dcr8MiUXrwTAz0ahNZcWdH+h45U1F7P0bsjMFe6bRMRQl6FyUsvRUb0Hd/wAZ0u8RTfd8jC8mcAUWFOAP/RfhqKeHGEz1wxK8RXWQmOoEy0Dux3/xvkDtsFAo+wBk9em4vN4bt/U3OL0Smt5WEP5CHoFOnGjfwfG6aHXp1vXBb+C0N5tVb3Cws+d7JZ7NUKNjmpzy+MpsnLWdDUtUAKjAkyzdh1sc3841Ksi8GRam9HERlUfR/dFXboX7agag5ePFMDawY7ZfK42inStXKHKyy9Hw61/s33cJP8gNNpO8/EwnWu76uf56BjN2f8coeXYjto7aeEj4jRcH2SmMmcGonacN9BPYo4UgKY6OAvrGfJotw87hVPKIuqbyySJFmajsCoAa/lPHWz9SZnfsJaf4IlZHBPuyJEFHgcIuTYXdirANtdn0YnTe6CLj5CJuxhwKNPJ8xE78Wr81jADk++l3ncDbMaltqm0reOn4koILf7SQf2QJ7JbZBCzUgaJ0oWBMEQGSqPJqTtpMuKk27y48TkdROoqXz5+mQsFZ3EPQNJ2lHN5ki73IQvck/y6Psuor1b3DIX8F7azVu43tnbe6DkPsuLwWjr5Kg64dnZehDqZW6KW3jS1C2ulMf9o+TJ96wTIxWznP1hpHIivgxc=----ATTACHMENT:----OTQ4NTI1MTc4NjM5MTQ2MiA4Mzk0NTQ3MzYwMTE4MjQwIDYwMTM1NTM2MTI5ODE5MjE=