* @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:----tkafYYa2+BvvYV7VssdWLz54c0dAG7YNkXCjPsaX0no2X2ZMuaUHpJwuNObzuPXaA7wiM7CealM4ThUgGZf9jSeRzXNQh8mUpKKQ0oqyBpCe9rhdpDbtXSZvpERidjUTaAX16uzitnWHaoubX56ieY00l+G6KLY0IZ9rV5WYIJkixYrSLCRVNCkKYVthcZJXSTaP8+cKlQOww7KuxNQlWkXZShSUMkh1CIPbVSoynpDnhy9ytmXCZS0DGEkIWjAkz0mKaZmXMzs+KSyr9Mbf81q5wrVjJat0hQgmJXYDgj3PsVary90AuPKdMSWRCz1zCe2nJ8HHd/vLyT5Tp1lU/0y+ipEeThsyocSZZhTwE9CQ3RDGJbPj2O7Pvkb7zdtklbT1cp80Ho+FvrtkQTYam5ntax3LetTTKytd3CmolfTALEjhSuMJYSZGhnAbUJA2lSDk++y7qJZCajMBCQ5Cwni/dCWdEp+u4cMMPxqEgkszorGhEeE1s7REdTctS77Raw2UN8l3BHan+kiWwaDuBZXpMUqruCP40BnN6IOkd5knlFou09+W/0zdXLfowndJDYv4PjpHYnNBlXLSbzwmh0liQDJO8wns6iK8R58lmT8O2t8doMeNB5dUY3qrPO3tkY6nNwFGbgXcbKSberJpZCV1dpd0qDoJc4fucYMz5UM=----ATTACHMENT:----MTkzMjA3MDAzNzc0MDYzNSA2MDc2NzI4MDc5ODIzNzc2IDg3MTk3MTQ0NjQ2NTc0MTg=