diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index c69aac223..daf202ef1 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -109,7 +109,33 @@ function links() $certs = $this->getCertificates($certsPath); - return $this->getLinks($this->sitesPath(), $certs); + return $this->getSites($this->sitesPath(), $certs); + } + + /** + * Pretty print out all parked links in Valet + * + * @return \Illuminate\Support\Collection + */ + function parked() + { + $certsPath = VALET_HOME_PATH.'/Certificates'; + + $this->files->ensureDirExists($certsPath, user()); + + $certs = $this->getCertificates($certsPath); + + $config = $this->config->read(); + $parkedLinks = collect(); + foreach ($config['paths'] as $path) { + if ($path === $this->sitesPath()) { + continue; + } + + $parkedLinks = $parkedLinks->merge($this->getSites($path, $certs)); + } + + return $parkedLinks; } /** @@ -139,18 +165,39 @@ function getCertificates($path) } /** - * Get list of links and present them formatted. + * @deprecated Use getSites instead which works for both normal and symlinked paths. * * @param string $path * @param \Illuminate\Support\Collection $certs * @return \Illuminate\Support\Collection */ function getLinks($path, $certs) + { + return $this->getSites($path, $certs); + } + + /** + * Get list of sites and return them formatted + * Will work for symlink and normal site paths + * + * @param $path + * @param $certs + * + * @return \Illuminate\Support\Collection + */ + function getSites($path, $certs) { $config = $this->config->read(); return collect($this->files->scandir($path))->mapWithKeys(function ($site) use ($path) { - return [$site => $this->files->readLink($path.'/'.$site)]; + $sitePath = $path.'/'.$site; + + if ($this->files->isLink($sitePath)) { + $realPath = $this->files->readLink($sitePath); + } else { + $realPath = $this->files->realpath($sitePath); + } + return [$site => $realPath]; })->map(function ($path, $site) use ($certs, $config) { $secured = $certs->has($site); $url = ($secured ? 'https': 'http').'://'.$site.'.'.$config['tld']; diff --git a/cli/valet.php b/cli/valet.php index 1154cdbb5..c4edcfa16 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -101,6 +101,15 @@ info(($path === null ? "This" : "The [{$path}]") . " directory has been added to Valet's paths."); })->descriptions('Register the current working (or specified) directory with Valet'); + /** + * Get all the current sites within paths parked with 'park {path}' + */ + $app->command('parked', function () { + $parked = Site::parked(); + + table(['Site', 'SSL', 'URL', 'Path'], $parked->all()); + })->descriptions('Display all the current sites within parked paths'); + /** * Remove the current working directory from the paths configuration. */ diff --git a/tests/SiteTest.php b/tests/SiteTest.php index 8e58543f6..544e44be8 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -50,6 +50,135 @@ public function test_get_certificates_will_return_with_multi_segment_tld() } + public function test_get_sites_will_return_if_secured() + { + $files = Mockery::mock(Filesystem::class); + $dirPath = '/Users/usertest/parkedpath'; + $files->shouldReceive('scandir') + ->once() + ->with($dirPath) + ->andReturn(['sitetwo', 'sitethree']); + $files->shouldReceive('isLink') + ->andReturn(false); + $files->shouldReceive('realpath') + ->twice() + ->andReturn($dirPath . '/sitetwo', $dirPath . '/sitethree'); + + $config = Mockery::mock(Configuration::class); + $config->shouldReceive('read') + ->once() + ->andReturn(['tld' => 'local']); + + swap(Filesystem::class, $files); + swap(Configuration::class, $config); + + /** @var Site $site */ + $site = resolve(Site::class); + + $certs = Mockery::mock(\Illuminate\Support\Collection::class); + $certs->shouldReceive('has') + ->twice() + ->with(Mockery::on(function ($arg) { + return $arg === 'sitetwo' || $arg === 'sitethree'; + })) + ->andReturn(false, true); + + $sites = $site->getSites($dirPath, $certs); + + $this->assertCount(2, $sites); + $this->assertSame([ + 'site' => 'sitetwo', + 'secured' => '', + 'url' => 'http://sitetwo.local', + 'path' => $dirPath . '/sitetwo', + ], $sites->first()); + $this->assertSame([ + 'site' => 'sitethree', + 'secured' => ' X', + 'url' => 'https://sitethree.local', + 'path' => $dirPath . '/sitethree', + ], $sites->last()); + } + + + public function test_get_sites_will_work_with_non_symlinked_path() + { + $files = Mockery::mock(Filesystem::class); + $dirPath = '/Users/usertest/parkedpath'; + $files->shouldReceive('scandir') + ->once() + ->with($dirPath) + ->andReturn(['sitetwo']); + $files->shouldReceive('isLink') + ->once() + ->with($dirPath . '/sitetwo') + ->andReturn(false); + $files->shouldReceive('realpath') + ->once() + ->with($dirPath . '/sitetwo') + ->andReturn($dirPath . '/sitetwo'); + + $config = Mockery::mock(Configuration::class); + $config->shouldReceive('read') + ->once() + ->andReturn(['tld' => 'local']); + + swap(Filesystem::class, $files); + swap(Configuration::class, $config); + + /** @var Site $site */ + $site = resolve(Site::class); + + $sites = $site->getSites($dirPath, collect()); + $this->assertCount(1, $sites); + $this->assertSame([ + 'site' => 'sitetwo', + 'secured' => '', + 'url' => 'http://sitetwo.local', + 'path' => $dirPath . '/sitetwo', + ], $sites->first()); + } + + + public function test_get_sites_will_work_with_symlinked_path() + { + $files = Mockery::mock(Filesystem::class); + $dirPath = '/Users/usertest/apath'; + $files->shouldReceive('scandir') + ->once() + ->with($dirPath) + ->andReturn(['siteone']); + $files->shouldReceive('isLink') + ->once() + ->with($dirPath . '/siteone') + ->andReturn(true); + $files->shouldReceive('readLink') + ->once() + ->with($dirPath . '/siteone') + ->andReturn($linkedPath = '/Users/usertest/linkedpath/siteone'); + + $config = Mockery::mock(Configuration::class); + $config->shouldReceive('read') + ->once() + ->andReturn(['tld' => 'local']); + + swap(Filesystem::class, $files); + swap(Configuration::class, $config); + + /** @var Site $site */ + $site = resolve(Site::class); + + $sites = $site->getSites($dirPath, collect()); + $this->assertCount(1, $sites); + $this->assertSame([ + 'site' => 'siteone', + 'secured' => '', + 'url' => 'http://siteone.local', + 'path' => $linkedPath, + ], $sites->first()); + } + + public function test_symlink_creates_symlink_to_given_path() { $files = Mockery::mock(Filesystem::class);