From e0659fb0d9ff27ed957082c8aac333497cc42906 Mon Sep 17 00:00:00 2001 From: tienvx Date: Wed, 17 Apr 2024 12:30:53 +0700 Subject: [PATCH] refactor(2.0): Add Parser --- src/Parser/Parser.php | 91 +++++++++++++++++ src/Parser/ParserInterface.php | 13 +++ tests/Unit/Parser/ParserTest.php | 161 +++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 src/Parser/Parser.php create mode 100644 src/Parser/ParserInterface.php create mode 100644 tests/Unit/Parser/ParserTest.php diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php new file mode 100644 index 0000000..154573b --- /dev/null +++ b/src/Parser/Parser.php @@ -0,0 +1,91 @@ +getExtra(); + + if (empty($extra['downloads'])) { + return []; + } + + $defaults = $extra['downloads']['*'] ?? []; + try { + foreach ((array) $extra['downloads'] as $id => $attributes) { + if ('*' === $id) { + continue; + } + + $extraDownloads[] = $this->parseSingle($package, $id, array_merge($defaults, $attributes)); + } + + return $extraDownloads; + } catch (\Exception $exception) { + $this->io->writeError(sprintf(' Skipped download extra files for package %s: %s', $package->getName(), $exception->getMessage())); + + return []; + } + } + + private function parseSingle(PackageInterface $package, string $id, array $attributes): PackageInterface + { + $attributeManager = new AttributeManager($attributes); + $this->addValidators($attributeManager, $id, $package); + if ($attributeManager->get(Attribute::TYPE)->isArchive()) { + $factory = new ExtraArchiveFactory($attributeManager); + } else { + $factory = new ExtraDownloadFactory($attributeManager); + } + + return $factory->create($id, $package); + } + + private function addValidators(AttributeManagerInterface $attributeManager, string $id, PackageInterface $parent): void + { + $validators = [ + new HashValidator($id, $parent), + new VersionValidator($id, $parent), + new VariablesValidator($id, $parent, $attributeManager), + new UrlValidator($id, $parent, $attributeManager), + new TypeValidator($id, $parent, $attributeManager), + new PathValidator($id, $parent, $attributeManager), + new IgnoreValidator($id, $parent, $attributeManager), + new ExecutableValidator( + $id, + $parent, + $attributeManager, + new PathValidator($id, $parent, $attributeManager, 'executable[*]') + ), + ]; + foreach ($validators as $validator) { + $attributeManager->addValidator($validator); + } + } +} diff --git a/src/Parser/ParserInterface.php b/src/Parser/ParserInterface.php new file mode 100644 index 0000000..9a67ddf --- /dev/null +++ b/src/Parser/ParserInterface.php @@ -0,0 +1,13 @@ + [ + '*' => [ + 'path' => 'common/path/to/dir', + ], + 'file1' => [ + 'url' => 'http://example.com/file1.zip', + 'version' => '1.2.3', + ], + 'file2' => [ + 'url' => 'http://example.com/file2.tar.gz', + 'executable' => [ + 'file1', + 'path/to/file2', + ], + ], + 'file3' => [ + 'type' => 'xz', + 'url' => 'http://example.com/{$id}.xz', + 'ignore' => [ + 'dir/*', + '!dir/file1', + ], + 'path' => 'path/to/dir', + ], + 'file4' => [ + 'type' => 'file', + 'url' => 'http://example.com/file.ext', + 'hash' => [ + 'algo' => 'md5', + 'value' => 'text', + ], + ], + ], + ]; + + protected function setUp(): void + { + $this->package = new Package('vendor/package-name', '1.0.0', 'v1.0.0'); + $this->io = $this->createMock(IOInterface::class); + $this->parser = new Parser($this->io); + } + + public function getEmptyTests(): array + { + return [ + [[]], + [['downloads' => null]], + [['downloads' => []]], + [['downloads' => ['*' => []]]], + ]; + } + + /** + * @dataProvider getEmptyTests + */ + public function testParseEmpty(array $extra): void + { + $this->package->setExtra($extra); + $this->assertSame([], $this->parser->parse($this->package)); + } + + public function testParseInvalid(): void + { + $this->extra['downloads']['file1']['url'] = '/path/to/file.zip'; + $this->package->setExtra($this->extra); + $this->io + ->expects($this->once()) + ->method('writeError') + ->with(' Skipped download extra files for package vendor/package-name: Attribute "url" of extra file "file1" defined in package "vendor/package-name" is invalid url.'); + $this->assertSame([], $this->parser->parse($this->package)); + } + + public function testParseValid(): void + { + $this->package->setExtra($this->extra); + $extraDownloads = $this->parser->parse($this->package); + $this->assertCount(4, $extraDownloads); + $this->assertExtraDownload( + $extraDownloads[0], + ExtraArchive::class, + 'file1', + '1.2.3', + 'http://example.com/file1.zip', + 'zip', + 'common/path/to/dir', + 'extra-download:archive' + ); + $this->assertExtraDownload( + $extraDownloads[1], + ExtraArchive::class, + 'file2', + ExtraDownload::FAKE_VERSION, + 'http://example.com/file2.tar.gz', + 'tar', + 'common/path/to/dir', + 'extra-download:archive' + ); + $this->assertExtraDownload( + $extraDownloads[2], + ExtraArchive::class, + 'file3', + ExtraDownload::FAKE_VERSION, + 'http://example.com/file3.xz', + 'xz', + 'path/to/dir', + 'extra-download:archive' + ); + $this->assertExtraDownload( + $extraDownloads[3], + ExtraDownload::class, + 'file4', + ExtraDownload::FAKE_VERSION, + 'http://example.com/file.ext', + 'file', + 'common/path/to/dir', + 'extra-download:file' + ); + } + + private function assertExtraDownload( + ExtraDownloadInterface $extraDownload, + string $class, + string $id, + string $version, + string $url, + string $distType, + string $path, + string $packageType, + ): void { + $this->assertInstanceOf($class, $extraDownload); + $this->assertSame(sprintf('vendor/package-name:%s', $id), $extraDownload->getName()); + $this->assertSame(ExtraDownload::FAKE_VERSION, $extraDownload->getVersion()); + $this->assertSame($version, $extraDownload->getPrettyVersion()); + $this->assertSame($url, $extraDownload->getDistUrl()); + $this->assertSame($distType, $extraDownload->getDistType()); + $this->assertSame($path, $extraDownload->getTargetDir()); + $this->assertSame('dist', $extraDownload->getInstallationSource()); + $this->assertSame($packageType, $extraDownload->getType()); + } +}