diff --git a/spec/Locator/ChangedFilesSpec.php b/spec/Locator/ChangedFilesSpec.php index 88d8ed7f2..ec796be2d 100644 --- a/spec/Locator/ChangedFilesSpec.php +++ b/spec/Locator/ChangedFilesSpec.php @@ -60,7 +60,7 @@ function it_will_list_all_diffed_files(GitRepository $repository, Filesystem $fi $result->shouldBeAnInstanceOf(FilesCollection::class); $result[0]->getPathname()->shouldBe('file1.txt'); $result[1]->getPathname()->shouldBe('file2.txt'); - $result->getIterator()->count()->shouldBe(2); + $result->shouldHaveCount(2); } function it_will_not_list_non_existing_files(GitRepository $repository, Filesystem $filesystem, Diff $diff, WorkingCopy $workingCopy) @@ -74,7 +74,7 @@ function it_will_not_list_non_existing_files(GitRepository $repository, Filesyst $result = $this->locateFromGitRepository(); $result->shouldBeAnInstanceOf(FilesCollection::class); - $result->getIterator()->count()->shouldBe(0); + $result->shouldHaveCount(0); } function it_will_list_all_diffed_files_from_raw_diff_input(GitRepository $repository, Filesystem $filesystem) @@ -96,6 +96,6 @@ function it_will_list_all_diffed_files_from_raw_diff_input(GitRepository $reposi $result = $this->locateFromRawDiffInput($rawDiff); $result->shouldBeAnInstanceOf(FilesCollection::class); $result[0]->getPathname()->shouldBe('file.txt'); - $result->getIterator()->count()->shouldBe(1); + $result->shouldHaveCount(1); } } diff --git a/spec/Locator/ListedFilesSpec.php b/spec/Locator/ListedFilesSpec.php index 728029ca6..34348db6d 100644 --- a/spec/Locator/ListedFilesSpec.php +++ b/spec/Locator/ListedFilesSpec.php @@ -32,6 +32,6 @@ function it_will_list_all_listed_files() $result->shouldBeAnInstanceOf(FilesCollection::class); $result[0]->getPathname()->shouldBe('file1.txt'); $result[1]->getPathname()->shouldBe('file2.txt'); - $result->getIterator()->count()->shouldBe(2); + $result->shouldHaveCount(2); } } diff --git a/src/Collection/FilesCollection.php b/src/Collection/FilesCollection.php index 20aa29d45..d96bc7c8d 100644 --- a/src/Collection/FilesCollection.php +++ b/src/Collection/FilesCollection.php @@ -213,12 +213,21 @@ public function filterByFileList(Traversable $fileList): FilesCollection public function ensureFiles(self $files): FilesCollection { - $newFiles = new self($this->toArray()); + $newFiles = new self(); + $knownPaths = []; + + foreach (parent::getIterator() as $value) { + $newFiles->add($value); + $knownPaths[$value->getPathname()] = true; + } foreach ($files as $file) { - if (!$newFiles->contains($file)) { - $newFiles->add($file); + $path = $file->getPathname(); + if (isset($knownPaths[$path])) { + continue; } + $newFiles->add($file); + $knownPaths[$path] = true; } return $newFiles; @@ -234,14 +243,28 @@ public function ignoreSymlinks(): FilesCollection /** * SplFileInfo cannot be serialized. Therefor, we help PHP a bit. * This stuff is used for running tasks in parallel. + * + * @psalm-suppress DocblockTypeContradiction + * @psalm-suppress RedundantConditionGivenDocblockType */ public function __serialize(): array { - return $this->map(function (SplFileInfo $fileInfo): string { - return $fileInfo instanceof SymfonySplFileInfo - ? $fileInfo->getRelativePathname() - : $fileInfo->getPathname(); - })->toArray(); + $paths = []; + foreach (parent::getIterator() as $value) { + if (\is_string($value)) { + $paths[] = $value; + continue; + } + if ($value instanceof SymfonySplFileInfo) { + $paths[] = $value->getRelativePathname(); + continue; + } + if ($value instanceof SplFileInfo) { + $paths[] = $value->getPathname(); + } + } + + return $paths; } /** @@ -250,25 +273,57 @@ public function __serialize(): array */ public function __unserialize(array $data): void { - $files = $data; $this->clear(); - foreach ($files as $file) { - $this->add(new SymfonySplFileInfo($file, dirname($file), $file)); + foreach ($data as $path) { + $this->add($path); } } /** - * Help Psalm out a bit: - * - * @return \ArrayIterator + * @return \Generator */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Generator { - return new \ArrayIterator($this->toArray()); + foreach (parent::getIterator() as $key => $value) { + yield $key => $this->hydrateFileInfo($value); + } } public function toFileList(): string { - return \implode(PHP_EOL, $this->toArray()); + $lines = []; + foreach ($this as $file) { + $lines[] = $file->getPathname(); + } + + return \implode(PHP_EOL, $lines); + } + + /** + * @return SplFileInfo|false + */ + public function first() + { + $value = parent::first(); + + return $value === false ? false : $this->hydrateFileInfo($value); + } + + /** + * @param mixed $value + */ + private function hydrateFileInfo($value): SplFileInfo + { + if ($value instanceof SplFileInfo) { + return $value; + } + + if (\is_string($value)) { + return new SymfonySplFileInfo($value, \dirname($value), $value); + } + + throw new \LogicException( + 'Unexpected element type in FilesCollection: ' . get_debug_type($value) + ); } } diff --git a/src/Console/Command/Git/CommitMsgCommand.php b/src/Console/Command/Git/CommitMsgCommand.php index 1f907fa82..77ac86745 100644 --- a/src/Console/Command/Git/CommitMsgCommand.php +++ b/src/Console/Command/Git/CommitMsgCommand.php @@ -119,6 +119,16 @@ public function execute(InputInterface $input, OutputInterface $output): int $results = $this->taskRunner->run($context); + if ($this->io->isVerbose()) { + $this->io->write([ + PHP_EOL, + sprintf( + 'Peak memory usage: %.1f MB', + (float) memory_get_peak_usage(true) / 1024.0 / 1024.0 + ) + ]); + } + return $results->isFailed() ? self::EXIT_CODE_NOK : self::EXIT_CODE_OK; } diff --git a/src/Console/Command/Git/PreCommitCommand.php b/src/Console/Command/Git/PreCommitCommand.php index 2e00bba15..e0e5143e3 100644 --- a/src/Console/Command/Git/PreCommitCommand.php +++ b/src/Console/Command/Git/PreCommitCommand.php @@ -90,6 +90,16 @@ public function execute(InputInterface $input, OutputInterface $output): int $results = $this->taskRunner->run($context); + if ($this->io->isVerbose()) { + $this->io->write([ + PHP_EOL, + sprintf( + 'Peak memory usage: %.1f MB', + (float) memory_get_peak_usage(true) / 1024.0 / 1024.0 + ) + ]); + } + return $results->isFailed() ? self::EXIT_CODE_NOK : self::EXIT_CODE_OK; } diff --git a/src/Console/Command/RunCommand.php b/src/Console/Command/RunCommand.php index e65ade451..03118d012 100644 --- a/src/Console/Command/RunCommand.php +++ b/src/Console/Command/RunCommand.php @@ -102,6 +102,16 @@ public function execute(InputInterface $input, OutputInterface $output): int $results = $this->taskRunner->run($context); + if ($this->io->isVerbose()) { + $this->io->write([ + PHP_EOL, + sprintf( + 'Peak memory usage: %.1f MB', + (float) memory_get_peak_usage(true) / 1024.0 / 1024.0 + ) + ]); + } + return $results->isFailed() ? self::EXIT_CODE_NOK : self::EXIT_CODE_OK; }