1
0
mirror of https://github.com/laravel/valet.git synced 2026-02-04 16:10:08 +01:00

refactor and tests

This commit is contained in:
Taylor Otwell
2016-05-08 23:04:16 -05:00
parent 5685b48f36
commit 075443b763
10 changed files with 360 additions and 131 deletions

View File

@@ -16,6 +16,7 @@
"autoload": {
"files": [
"compatibility.php",
"facades.php",
"helpers.php"
],
"psr-4": {

37
facades.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
namespace Valet\Facades;
class Facade
{
/**
* The key for the binding in the container.
*
* @return string
*/
public static function containerKey()
{
return 'Valet\\'.basename(str_replace('\\', '/', get_called_class()));
}
/**
* Call a non-static method on the facade.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public static function __callStatic($method, $parameters)
{
return call_user_func_array([resolve(static::containerKey()), $method], $parameters);
}
}
class Brew extends Facade {}
class Caddy extends Facade {}
class CommandLine extends Facade {}
class Configuration extends Facade {}
class DnsMasq extends Facade {}
class Filesystem extends Facade {}
class PhpFpm extends Facade {}
class Site extends Facade {}

View File

@@ -76,15 +76,29 @@ function writeBaseConfiguration()
* Add the given path to the configuration.
*
* @param string $path
* @return array
* @param bool $prepend
* @return void
*/
function addPath($path)
function addPath($path, $prepend = false)
{
$this->write(tap($this->read(), function (&$config) use ($path) {
$config['paths'] = collect($config['paths'])->push($path)->unique()->all();
$this->write(tap($this->read(), function (&$config) use ($path, $prepend) {
$method = $prepend ? 'prepend' : 'push';
$config['paths'] = collect($config['paths'])->{$method}($path)->unique()->all();
}));
}
/**
* Prepend the given path to the configuration.
*
* @param string $path
* @return void
*/
function prependPath($path)
{
return $this->addPath($path, true);
}
/**
* Add the given path to the configuration.
*

View File

@@ -10,7 +10,7 @@ class Filesystem
* @param string $path
* @return bool
*/
public function isDir($path)
function isDir($path)
{
return is_dir($path);
}
@@ -23,7 +23,7 @@ public function isDir($path)
* @param int $mode
* @return void
*/
public function mkdir($path, $owner = null, $mode = 0755)
function mkdir($path, $owner = null, $mode = 0755)
{
mkdir($path, $mode);
@@ -40,7 +40,7 @@ public function mkdir($path, $owner = null, $mode = 0755)
* @param int $mode
* @return void
*/
public function ensureDirExists($path, $owner = null, $mode = 0755)
function ensureDirExists($path, $owner = null, $mode = 0755)
{
if (! $this->isDir($path)) {
$this->mkdir($path, $owner, $mode);
@@ -54,7 +54,7 @@ public function ensureDirExists($path, $owner = null, $mode = 0755)
* @param int $mode
* @return void
*/
public function mkdirAsUser($path, $mode = 0755)
function mkdirAsUser($path, $mode = 0755)
{
return $this->mkdir($path, user(), $mode);
}
@@ -64,15 +64,17 @@ public function mkdirAsUser($path, $mode = 0755)
*
* @param string $path
* @param string|null $owner
* @return void
* @return string
*/
public function touch($path, $owner = null)
function touch($path, $owner = null)
{
touch($path);
if ($owner) {
$this->chown($path, $owner);
}
return $path;
}
/**
@@ -81,7 +83,7 @@ public function touch($path, $owner = null)
* @param string $path
* @return void
*/
public function touchAsUser($path)
function touchAsUser($path)
{
return $this->touch($path, user());
}
@@ -92,7 +94,7 @@ public function touchAsUser($path)
* @param string $path
* @return bool
*/
public function exists($path)
function exists($path)
{
return file_exists($path);
}
@@ -103,7 +105,7 @@ public function exists($path)
* @param string $path
* @return string
*/
public function get($path)
function get($path)
{
return file_get_contents($path);
}
@@ -116,7 +118,7 @@ public function get($path)
* @param string|null $owner
* @return string
*/
public function put($path, $contents, $owner = null)
function put($path, $contents, $owner = null)
{
file_put_contents($path, $contents);
@@ -132,7 +134,7 @@ public function put($path, $contents, $owner = null)
* @param string $contents
* @return string
*/
public function putAsUser($path, $contents)
function putAsUser($path, $contents)
{
return $this->put($path, $contents, user());
}
@@ -145,7 +147,7 @@ public function putAsUser($path, $contents)
* @param string|null $owner
* @return void
*/
public function append($path, $contents, $owner = null)
function append($path, $contents, $owner = null)
{
file_put_contents($path, $contents, FILE_APPEND);
@@ -161,7 +163,7 @@ public function append($path, $contents, $owner = null)
* @param string $contents
* @return void
*/
public function appendAsUser($path, $contents)
function appendAsUser($path, $contents)
{
return $this->append($path, $contents, user());
}
@@ -173,7 +175,7 @@ public function appendAsUser($path, $contents)
* @param string $to
* @return void
*/
public function copy($from, $to)
function copy($from, $to)
{
copy($from, $to);
}
@@ -185,20 +187,36 @@ public function copy($from, $to)
* @param string $to
* @return void
*/
public function copyAsUser($from, $to)
function copyAsUser($from, $to)
{
copy($from, $to);
$this->chown($to, user());
}
/**
* Create a symlink to the given target.
*
* @param string $target
* @param string $link
* @return void
*/
function symlink($target, $link)
{
if ($this->exists($link)) {
$this->unlink($link);
}
symlink($target, $link);
}
/**
* Delete the file at the given path.
*
* @param string $path
* @return void
*/
public function unlink($path)
function unlink($path)
{
@unlink($path);
}
@@ -209,7 +227,7 @@ public function unlink($path)
* @param string $path
* @param string $user
*/
public function chown($path, $user)
function chown($path, $user)
{
chown($path, $user);
}
@@ -220,7 +238,7 @@ public function chown($path, $user)
* @param string $path
* @param string $group
*/
public function chgrp($path, $group)
function chgrp($path, $group)
{
chgrp($path, $group);
}
@@ -231,7 +249,7 @@ public function chgrp($path, $group)
* @param string $path
* @return string
*/
public function realpath($path)
function realpath($path)
{
return realpath($path);
}
@@ -242,7 +260,7 @@ public function realpath($path)
* @param string $path
* @return bool
*/
public function isLink($path)
function isLink($path)
{
return is_link($path);
}
@@ -253,8 +271,50 @@ public function isLink($path)
* @param string $path
* @return string
*/
public function readLink($path)
function readLink($path)
{
return read_link($path);
return readlink($path);
}
/**
* Remove all of the broken symbolic links at the given path.
*
* @param string $path
* @return void
*/
function removeBrokenLinksAt($path)
{
collect($this->scandir($path))
->filter(function ($file) use ($path) {
return $this->isBrokenLink($path.'/'.$file);
})
->each(function ($file) use ($path) {
$this->unlink($path.'/'.$file);
});
}
/**
* Determine if the given path is a broken symbolic link.
*
* @param string $path
* @return bool
*/
function isBrokenLink($path)
{
return is_link($path) && ! file_exists($path);
}
/**
* Scan the given directory path.
*
* @param string $path
* @return array
*/
function scandir($path)
{
return collect(scandir($path))
->reject(function ($file) {
return in_array($file, ['.', '..']);
})->values()->all();
}
}

View File

@@ -29,10 +29,9 @@ function __construct(Brew $brew, CommandLine $cli)
/**
* Install and configure DnsMasq.
*
* @param OutputInterface $output
* @return void
*/
function install($output)
function install()
{
$this->brew->ensureInstalled('php70', $this->taps);

View File

@@ -2,31 +2,43 @@
namespace Valet;
use Exception;
use DomainException;
class Site
{
var $config, $files;
/**
* Create a new Site instance.
*
* @param Configuration $config
* @param Filesystem $files
* @return void
*/
function __construct(Configuration $config, Filesystem $files)
{
$this->files = $files;
$this->config = $config;
}
/**
* Link the current working directory with the given name.
*
* @param string $target
* @param string $name
* @return string
*/
public static function link($name)
function link($target, $link)
{
if (! is_dir($linkPath = VALET_HOME_PATH.'/Sites')) {
mkdir($linkPath, 0755);
}
$this->files->ensureDirExists(
$linkPath = $this->sitesPath(), user()
);
Configuration::addPath($linkPath);
$this->config->prependPath($linkPath);
if (file_exists($linkPath.'/'.$name)) {
throw new Exception("A symbolic link with this name already exists.");
}
$this->files->symlink($target, $linkPath.'/'.$link);
symlink(getcwd(), $linkPath.'/'.$name);
return $linkPath;
return $linkPath.'/'.$link;
}
/**
@@ -35,11 +47,11 @@ public static function link($name)
* @param string $name
* @return void
*/
public static function unlink($name)
function unlink($name)
{
quietly('rm '.VALET_HOME_PATH.'/Sites/'.$name);
return true;
if ($this->files->exists($path = $this->sitesPath().'/'.$name)) {
$this->files->unlink($path);
}
}
/**
@@ -47,52 +59,43 @@ public static function unlink($name)
*
* @return void
*/
public static function pruneLinks()
function pruneLinks()
{
if (! is_dir(VALET_HOME_PATH.'/Sites')) {
return;
}
foreach (scandir(VALET_HOME_PATH.'/Sites') as $file) {
if (in_array($file, ['.', '..'])) {
continue;
}
if (is_link($linkPath = VALET_HOME_PATH.'/Sites/'.$file) && ! file_exists($linkPath)) {
quietly('rm '.$linkPath);
}
if ($this->files->isDir($sitesPath = $this->sitesPath())) {
$this->files->removeBrokenLinksAt($sitesPath);
}
}
/**
* Get all of the log files for all sites.
*
* @param array $paths
* @return array
*/
public static function logs()
function logs($paths)
{
$paths = Configuration::read()['paths'];
$files = [];
$files = collect();
foreach ($paths as $path) {
foreach (scandir($path) as $directory) {
$files = $files->merge(collect($this->files->scandir($path))->map(function ($directory) use ($path) {
$logPath = $path.'/'.$directory.'/storage/logs/laravel.log';
if (in_array($directory, ['.', '..'])) {
continue;
if ($this->files->isDir(dirname($logPath))) {
return $this->files->touch($logPath);
}
if (file_exists($logPath)) {
$files[] = $logPath;
} elseif (is_dir(dirname($logPath))) {
touch($logPath);
$files[] = $logPath;
}
}
})->filter());
}
return $files;
return $files->values()->all();
}
/**
* Get the path to the linked Valet sites.
*
* @return string
*/
function sitesPath()
{
return VALET_HOME_PATH.'/Sites';
}
}

25
tests/FilesystemTest.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
use Valet\Filesystem;
class FilesystemTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
exec('rm -rf '.__DIR__.'/output');
mkdir(__DIR__.'/output');
touch(__DIR__.'/output/.gitkeep');
}
public function test_remove_broken_links_removes_broken_symlinks()
{
$files = new Filesystem;
file_put_contents(__DIR__.'/output/file.out', 'test');
symlink(__DIR__.'/output/file.out', __DIR__.'/output/file.link');
$this->assertTrue(file_exists(__DIR__.'/output/file.link'));
unlink(__DIR__.'/output/file.out');
$files->removeBrokenLinksAt(__DIR__.'/output');
$this->assertFalse(file_exists(__DIR__.'/output/file.link'));
}
}

84
tests/SiteTest.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
use Valet\Site;
use Valet\Filesystem;
use Valet\Configuration;
use Illuminate\Container\Container;
class SiteTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$_SERVER['SUDO_USER'] = 'Taylor';
Container::setInstance(new Container);
}
public function tearDown()
{
exec('rm -rf '.__DIR__.'/output');
mkdir(__DIR__.'/output');
touch(__DIR__.'/output/.gitkeep');
Mockery::close();
}
public function test_symlink_creates_symlink_to_given_path()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('ensureDirExists')->once()->with(VALET_HOME_PATH.'/Sites', user());
$config = Mockery::mock(Configuration::class);
$config->shouldReceive('prependPath')->once()->with(VALET_HOME_PATH.'/Sites');
$files->shouldReceive('symlink')->once()->with('target', VALET_HOME_PATH.'/Sites/link');
swap(Filesystem::class, $files);
swap(Configuration::class, $config);
$linkPath = resolve(Site::class)->link('target', 'link');
$this->assertEquals(VALET_HOME_PATH.'/Sites/link', $linkPath);
}
public function test_unlink_removes_existing_symlink()
{
file_put_contents(__DIR__.'/output/file.out', 'test');
symlink(__DIR__.'/output/file.out', __DIR__.'/output/link');
$site = resolve(StubForRemovingLinks::class);
$site->unlink('link');
$this->assertFalse(file_exists(__DIR__.'/output/link'));
$site = resolve(StubForRemovingLinks::class);
$site->unlink('link');
$this->assertFalse(file_exists(__DIR__.'/output/link'));
}
public function test_prune_links_removes_broken_symlinks_in_sites_path()
{
file_put_contents(__DIR__.'/output/file.out', 'test');
symlink(__DIR__.'/output/file.out', __DIR__.'/output/link');
unlink(__DIR__.'/output/file.out');
$site = resolve(StubForRemovingLinks::class);
$site->pruneLinks();
$this->assertFalse(file_exists(__DIR__.'/output/link'));
}
public function test_logs_method_returns_array_of_log_files()
{
$logs = resolve(Site::class)->logs([__DIR__.'/test-directory-for-logs']);
$this->assertEquals(__DIR__.'/test-directory-for-logs/project/storage/logs/laravel.log', $logs[0]);
unlink(__DIR__.'/test-directory-for-logs/project/storage/logs/laravel.log');
}
}
class StubForRemovingLinks extends Site
{
function sitesPath()
{
return __DIR__.'/output';
}
}

120
valet.php
View File

@@ -11,6 +11,14 @@
}
use Silly\Application;
use Valet\Facades\Brew;
use Valet\Facades\Site;
use Valet\Facades\Caddy;
use Valet\Facades\PhpFpm;
use Valet\Facades\DnsMasq;
use Valet\Facades\Filesystem;
use Valet\Facades\CommandLine;
use Valet\Facades\Configuration;
use Illuminate\Container\Container;
/**
@@ -24,28 +32,28 @@
* Prune missing directories and symbolic links on every command.
*/
if (is_dir(VALET_HOME_PATH)) {
Valet\Configuration::prune();
Configuration::prune();
Valet\Site::pruneLinks();
Site::pruneLinks();
}
/**
* Allow Valet to be run more conveniently by allowing the Node proxy to run password-less sudo.
*/
$app->command('install', function ($output) {
$app->command('install', function () {
should_be_sudo();
Valet\Caddy::stop();
Caddy::stop();
Valet\Configuration::install();
Configuration::install();
Valet\Caddy::install();
Caddy::install();
Valet\PhpFpm::install($output);
PhpFpm::install();
Valet\DnsMasq::install($output);
DnsMasq::install();
Valet\Caddy::restart();
Caddy::restart();
output(PHP_EOL.'<info>Valet installed successfully!</info>');
});
@@ -53,52 +61,52 @@
/**
* Change the domain currently being used by Valet.
*/
$app->command('domain domain', function ($domain, $output) {
$app->command('domain domain', function ($domain) {
should_be_sudo();
$domain = trim($domain, '.');
Valet\DnsMasq::updateDomain(Valet\Configuration::read()['domain'], $domain);
DnsMasq::updateDomain(Configuration::read()['domain'], $domain);
Valet\Configuration::updateKey('domain', $domain);
Configuration::updateKey('domain', $domain);
$output->writeln('<info>Your Valet domain has been updated to ['.$domain.'].</info>');
output('<info>Your Valet domain has been updated to ['.$domain.'].</info>');
});
/**
* Get the domain currently being used by Valet.
*/
$app->command('current-domain', function ($output) {
$output->writeln(Valet\Configuration::read()['domain']);
$app->command('current-domain', function () {
output(Configuration::read()['domain']);
});
/**
* Add the current working directory to the paths configuration.
*/
$app->command('park', function ($output) {
Valet\Configuration::addPath(getcwd());
$app->command('park', function () {
Configuration::addPath(getcwd());
$output->writeln("<info>This directory has been added to Valet's paths.</info>");
output("<info>This directory has been added to Valet's paths.</info>");
});
/**
* Remove the current working directory to the paths configuration.
*/
$app->command('forget', function ($output) {
Valet\Configuration::removePath(getcwd());
$app->command('forget', function () {
Configuration::removePath(getcwd());
$output->writeln("<info>This directory has been removed from Valet's paths.</info>");
output("<info>This directory has been removed from Valet's paths.</info>");
});
/**
* Register a symbolic link with Valet.
*/
$app->command('link [name]', function ($name, $output) {
$app->command('link [name]', function ($name) {
$name = $name ?: basename(getcwd());
$linkPath = Valet\Site::link($name);
$linkPath = Site::link(getcwd(), $name);
$output->writeln('<info>A ['.$name.'] symbolic link has been created in ['.$linkPath.'].</info>');
output('<info>A ['.$name.'] symbolic link has been created in ['.$linkPath.'].</info>');
});
/**
@@ -111,62 +119,60 @@
/**
* Unlink a link from the Valet links directory.
*/
$app->command('unlink [name]', function ($name, $output) {
$app->command('unlink [name]', function ($name) {
$name = $name ?: basename(getcwd());
if (Valet\Site::unlink($name)) {
$output->writeln('<info>The ['.$name.'] symbolic link has been removed.</info>');
} else {
$output->writeln('<fg=red>A symbolic link with this name does not exist.</>');
}
Site::unlink($name);
output('<info>The ['.$name.'] symbolic link has been removed.</info>');
});
/**
* Determine which Valet driver the current directory is using.
*/
$app->command('which', function ($output) {
$app->command('which', function () {
require __DIR__.'/drivers/require.php';
$driver = ValetDriver::assign(getcwd(), basename(getcwd()), '/');
if ($driver) {
$output->writeln('<info>This site is served by ['.get_class($driver).'].</info>');
output('<info>This site is served by ['.get_class($driver).'].</info>');
} else {
$output->writeln('<fg=red>Valet could not determine which driver to use for this site.</>');
output('<fg=red>Valet could not determine which driver to use for this site.</>');
}
});
/**
* Stream all of the logs for all sites.
*/
$app->command('logs', function ($output) {
$files = Valet\Site::logs();
$app->command('logs', function () {
$files = Site::logs(Configuration::read()['paths']);
if (count($files) > 0) {
passthru('tail -f '.implode(' ', $files));
} else {
$output->writeln('<fg=red>No log files were found.</>');
output('<fg=red>No log files were found.</>');
}
});
/**
* Display all of the registered paths.
*/
$app->command('paths', function ($output) {
$paths = Valet\Configuration::read()['paths'];
$app->command('paths', function () {
$paths = Configuration::read()['paths'];
if (count($paths) > 0) {
$output->writeln(json_encode($paths, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
output(json_encode($paths, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
} else {
$output->writeln('No paths have been registered.');
output('No paths have been registered.');
}
});
/**
* Echo the currently tunneled URL.
*/
$app->command('fetch-share-url', function ($output) {
retry(20, function () use ($output) {
$app->command('fetch-share-url', function () {
retry(20, function () {
$response = Httpful\Request::get('http://127.0.0.1:4040/api/tunnels')->send();
$body = $response->body;
@@ -186,48 +192,48 @@
/**
* Start the daemon services.
*/
$app->command('start', function ($output) {
$app->command('start', function () {
should_be_sudo();
Valet\PhpFpm::restart();
Valet\Caddy::restart();
PhpFpm::restart();
Caddy::restart();
$output->writeln('<info>Valet services have been started.</info>');
output('<info>Valet services have been started.</info>');
});
/**
* Restart the daemon services.
*/
$app->command('restart', function ($output) {
$app->command('restart', function () {
should_be_sudo();
Valet\PhpFpm::restart();
Valet\Caddy::restart();
PhpFpm::restart();
Caddy::restart();
$output->writeln('<info>Valet services have been restarted.</info>');
output('<info>Valet services have been restarted.</info>');
});
/**
* Stop the daemon services.
*/
$app->command('stop', function ($output) {
$app->command('stop', function () {
should_be_sudo();
Valet\PhpFpm::stop();
Valet\Caddy::stop();
PhpFpm::stop();
Caddy::stop();
$output->writeln('<info>Valet services have been stopped.</info>');
output('<info>Valet services have been stopped.</info>');
});
/**
* Uninstall Valet entirely.
*/
$app->command('uninstall', function ($output) {
$app->command('uninstall', function () {
should_be_sudo();
Valet\Caddy::uninstall();
Caddy::uninstall();
$output->writeln('<info>Valet has been uninstalled.</info>');
output('<info>Valet has been uninstalled.</info>');
});
/**