diff --git a/composer.json b/composer.json index 0e7612d9..72b65a55 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,8 @@ "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1", "drupal/coder": "^8.3", "phpstan/phpstan": "^1.0", - "phpstan/phpstan-symfony": "^1.0" + "phpstan/phpstan-symfony": "^1.0", + "phpspec/prophecy-phpunit": "^2.0" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 39ada982..436dcbf1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "da48e82f75f525d6ecdaec3949b37bcf", + "content-hash": "d7b21e7f6f684fb2810a400a34859924", "packages": [ { "name": "composer/semver", @@ -4638,6 +4638,58 @@ }, "time": "2021-12-08T12:19:24+00:00" }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/2d7a9df55f257d2cba9b1d0c0963a54960657177", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.3", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.0.1" + }, + "time": "2020-07-09T08:33:42+00:00" + }, { "name": "phpstan/phpdoc-parser", "version": "1.2.0", diff --git a/src/Configuration/ConfigurationService.php b/src/Configuration/ConfigurationService.php index 2a92be90..9eb6f500 100644 --- a/src/Configuration/ConfigurationService.php +++ b/src/Configuration/ConfigurationService.php @@ -382,7 +382,7 @@ public function resolveRelativeInheritanceRefs( $item = $child->getValue(); // Skip urls and absolute paths: - if ($item[0] === '/' || Utilities::isHttpUrl($item)) { + if ($item[0] === '/' || Utilities::isHttpUrl($item) || Utilities::isPharUrl($item)) { continue; } @@ -549,7 +549,7 @@ public function readHttpResource(string $resource) if (!$this->offlineMode) { try { $this->logger->info(sprintf('Read remote file from `%s`', $resource)); - $url = parse_url($resource); + $url = Utilities::parseUrl($resource); $url['path'] = urlencode($url['path']); $url['path'] = str_replace('%2F', '/', $url['path']); $resource = http_build_url($url); diff --git a/src/Method/ResticMethod.php b/src/Method/ResticMethod.php index 0910a1a6..c4161c7d 100644 --- a/src/Method/ResticMethod.php +++ b/src/Method/ResticMethod.php @@ -337,7 +337,7 @@ protected function ensureKnownHosts( ): void { $repository = $host_config['restic']['repository']; if (substr($repository, 0, 5) == 'sftp:') { - $a = parse_url($repository); + $a = Utilities::parseUrl($repository); $known_hosts = [ sprintf("%s:%d", $a['host'], $a['port'] ?? 22) ]; diff --git a/src/Scaffolder/Scaffolder.php b/src/Scaffolder/Scaffolder.php index 2e0560ff..f9629508 100644 --- a/src/Scaffolder/Scaffolder.php +++ b/src/Scaffolder/Scaffolder.php @@ -98,7 +98,8 @@ public function scaffold( $root_path = dirname($url); try { if (!Utilities::isHttpUrl($url)) { - $fullpath = realpath($url); + $is_phar = Utilities::isPharUrl($url); + $fullpath = $is_phar ? $url : realpath($url); if (empty($fullpath)) { throw new \RuntimeException(sprintf('Could not find file at `%s`!', $url)); } @@ -384,6 +385,7 @@ public function getLocalScaffoldFile($name) ? Phar::running() . '/config/scaffold' : realpath(__DIR__ . '/../../config/scaffold/'); + print_r($rootFolder); return $rootFolder . '/' . $name; } diff --git a/src/Utilities/Utilities.php b/src/Utilities/Utilities.php index 18afcb51..6c3e9e10 100644 --- a/src/Utilities/Utilities.php +++ b/src/Utilities/Utilities.php @@ -603,9 +603,26 @@ public static function getTempFileName(HostConfig $host_config, $str): string basename($str); } + /** + * Custom parse_url implementation, as parse_url does not support phar-scheme. + */ + public static function parseUrl($url) + { + if (self::isPharUrl($url)) { + return [ + 'scheme' => 'phar', + 'path' => str_replace('phar://', '//', $url), + ]; + } + return parse_url($url); + } + + public static function resolveRelativePaths(string $url): string { - $result = parse_url($url); + $result = self::parseUrl($url); + print_r($url); + print_r($result); $filename = $result['path']; $path = []; $parts = explode('/', $filename); @@ -645,7 +662,7 @@ public static function buildUrl($components) if (!empty($components['username']) && !empty($components['password'])) { $url .= $components['username'] . ':' . $components['password'] . '@'; } - if (!empty($components['scheme'])) { + if (!empty($components['host'])) { $url .= $components['host']; } if (!empty($components['port'])) { @@ -670,4 +687,12 @@ public static function isHttpUrl($url): bool { return (substr($url, 0, 4) === 'http') && (strpos($url, '://') !== false); } + + /** + * Returns true if url is a phar url. + */ + public static function isPharUrl($url): bool + { + return (substr($url, 0, 4) === 'phar') && (strpos($url, '://') !== false); + } } diff --git a/symfony.lock b/symfony.lock index a1247d6d..e4d98c1f 100644 --- a/symfony.lock +++ b/symfony.lock @@ -83,6 +83,9 @@ "phpspec/prophecy": { "version": "1.8.0" }, + "phpspec/prophecy-phpunit": { + "version": "v2.0.1" + }, "phpstan/phpdoc-parser": { "version": "1.2.0" }, diff --git a/tests/UtilitiesTest.php b/tests/UtilitiesTest.php index 661c58d3..185f66fe 100644 --- a/tests/UtilitiesTest.php +++ b/tests/UtilitiesTest.php @@ -361,4 +361,22 @@ public function testArgumentsParsing() $args = Utilities::parseArguments("password=aFQd=BDq_ys9j72frDgM"); $this->assertEquals("aFQd=BDq_ys9j72frDgM", $args['password']); } + + public function testRelativePharUrls() + { + $url = 'phar:///usr/local/bin/phab/config/scaffold/mbb/./mbb-base.yml'; + $this->assertEquals( + 'phar:///usr/local/bin/phab/config/scaffold/mbb/mbb-base.yml', + Utilities::resolveRelativePaths($url) + ); + } + + public function testRelativeFileUrls() + { + $url = 'file:///usr/local/bin/phab/config/scaffold/mbb/./mbb-base.yml'; + $this->assertEquals( + 'file:///usr/local/bin/phab/config/scaffold/mbb/mbb-base.yml', + Utilities::resolveRelativePaths($url) + ); + } } diff --git a/tests/WorkspaceCreateUpdateTest.php b/tests/WorkspaceCreateUpdateTest.php index 0756c76a..078faac1 100644 --- a/tests/WorkspaceCreateUpdateTest.php +++ b/tests/WorkspaceCreateUpdateTest.php @@ -5,32 +5,45 @@ use Phabalicious\Command\WorkspaceCreateCommand; use Phabalicious\Command\WorkspaceUpdateCommand; use Phabalicious\Configuration\ConfigurationService; +use Phabalicious\Configuration\Storage\Node; use Phabalicious\Method\LocalMethod; use Phabalicious\Method\MethodFactory; use Phabalicious\Method\ScriptMethod; +use Phabalicious\Method\TaskContext; +use Phabalicious\Method\TaskContextInterface; +use Phabalicious\Scaffolder\Options; +use Phabalicious\Scaffolder\Scaffolder; use Phabalicious\Utilities\Utilities; +use Prophecy\PhpUnit\ProphecyTrait; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Application; +use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Yaml\Yaml; class WorkspaceCreateUpdateTest extends PhabTestCase { + + use ProphecyTrait; + /** @var Application */ protected $application; + protected $configuration; + public function setup(): void { $this->application = new Application(); $this->application->setVersion(Utilities::FALLBACK_VERSION); $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); - $configuration = new ConfigurationService($this->application, $logger); - $method_factory = new MethodFactory($configuration, $logger); + $this->configuration = new ConfigurationService($this->application, $logger); + $method_factory = new MethodFactory($this->configuration, $logger); $method_factory->addMethod(new LocalMethod($logger)); $method_factory->addMethod(new ScriptMethod($logger)); - $this->application->add(new WorkspaceCreateCommand($configuration, $method_factory)); - $this->application->add(new WorkspaceUpdateCommand($configuration, $method_factory)); + $this->application->add(new WorkspaceCreateCommand($this->configuration, $method_factory)); + $this->application->add(new WorkspaceUpdateCommand($this->configuration, $method_factory)); } private function prepareTarget()