mirror of
https://github.com/laravel/valet.git
synced 2026-02-05 16:40:05 +01:00
progress refactoring
This commit is contained in:
@@ -24,9 +24,15 @@
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"illuminate/container": "~5.1",
|
||||
"mnapoli/silly": "~1.0",
|
||||
"symfony/process": "~2.7|~3.0",
|
||||
"nategood/httpful": "~0.2"
|
||||
"nategood/httpful": "~0.2",
|
||||
"tightenco/collect": "^5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "0.9.*",
|
||||
"phpunit/phpunit": "~5.0"
|
||||
},
|
||||
"bin": [
|
||||
"valet"
|
||||
|
||||
99
helpers.php
99
helpers.php
@@ -1,15 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Define the ~/.valet path as a constant.
|
||||
*/
|
||||
define('VALET_HOME_PATH', $_SERVER['HOME'].'/.valet');
|
||||
|
||||
/**
|
||||
* Simple global function to run commands.
|
||||
* Output the given text to the console.
|
||||
*
|
||||
* @param string $output
|
||||
* @return void
|
||||
*/
|
||||
function quietly($command)
|
||||
function output($output)
|
||||
{
|
||||
(new Process($command))->run();
|
||||
(new Symfony\Component\Console\Output\ConsoleOutput)->writeln($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given class from the container.
|
||||
*
|
||||
* @param string $class
|
||||
* @return mixed
|
||||
*/
|
||||
function resolve($class)
|
||||
{
|
||||
return Container::getInstance()->make($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the given class implementation in the container.
|
||||
*
|
||||
* @param string $class
|
||||
* @param mixed $instance
|
||||
* @return void
|
||||
*/
|
||||
function swap($class, $instance)
|
||||
{
|
||||
Container::getInstance()->instance($class, $instance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,43 +70,6 @@ function retry($retries, $fn, $sleep = 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given command.
|
||||
*
|
||||
* @param string $command
|
||||
* @param callable $onError
|
||||
* @return string
|
||||
*/
|
||||
function run($command, callable $onError = null)
|
||||
{
|
||||
return run_as_root('sudo -u '.$_SERVER['SUDO_USER'].' '.$command, $onError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given command as root.
|
||||
*
|
||||
* @param string $command
|
||||
* @param callable $onError
|
||||
* @return string
|
||||
*/
|
||||
function run_as_root($command, callable $onError = null)
|
||||
{
|
||||
$onError = $onError ?: function () {};
|
||||
|
||||
$process = new Process($command);
|
||||
|
||||
$processOutput = '';
|
||||
$process->run(function ($type, $line) use (&$processOutput) {
|
||||
$processOutput .= $line;
|
||||
});
|
||||
|
||||
if ($process->getExitCode() > 0) {
|
||||
$onError($process->getExitCode(), $processOutput);
|
||||
}
|
||||
|
||||
return $processOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the script is currently running as "sudo".
|
||||
*
|
||||
@@ -88,3 +81,29 @@ function should_be_sudo()
|
||||
throw new Exception('This command must be run with sudo.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tap the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param callable $callback
|
||||
* @return mixed
|
||||
*/
|
||||
function tap($value, callable $callback)
|
||||
{
|
||||
$callback($value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user
|
||||
*/
|
||||
function user()
|
||||
{
|
||||
if (! isset($_SERVER['SUDO_USER'])) {
|
||||
return $_SERVER['USER'];
|
||||
}
|
||||
|
||||
return $_SERVER['SUDO_USER'];
|
||||
}
|
||||
|
||||
19
phpunit.xml
Normal file
19
phpunit.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false">
|
||||
<testsuites>
|
||||
<testsuite name="Valet Test Suite">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
51
src/Brew.php
51
src/Brew.php
@@ -3,18 +3,35 @@
|
||||
namespace Valet;
|
||||
|
||||
use Exception;
|
||||
use DomainException;
|
||||
|
||||
class Brew
|
||||
{
|
||||
var $cli;
|
||||
var $files;
|
||||
|
||||
/**
|
||||
* Create a new Brew instance.
|
||||
*
|
||||
* @param CommandLine $cli
|
||||
* @param Filesystem $files
|
||||
* @return void
|
||||
*/
|
||||
function __construct(CommandLine $cli, Filesystem $files)
|
||||
{
|
||||
$this->cli = $cli;
|
||||
$this->files = $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given formula is installed.
|
||||
*
|
||||
* @param string $formula
|
||||
* @return bool
|
||||
*/
|
||||
public static function installed($formula)
|
||||
function installed($formula)
|
||||
{
|
||||
return in_array($formula, explode(PHP_EOL, run('brew list | grep '.$formula)));
|
||||
return in_array($formula, explode(PHP_EOL, $this->cli->run('brew list | grep '.$formula)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,9 +39,9 @@ public static function installed($formula)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasInstalledPhp()
|
||||
function hasInstalledPhp()
|
||||
{
|
||||
return static::installed('php70') || static::installed('php56');
|
||||
return $this->installed('php70') || $this->installed('php56');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,12 +50,12 @@ public static function hasInstalledPhp()
|
||||
* @param dynamic[string] $formula
|
||||
* @return void
|
||||
*/
|
||||
public static function tap($formulas)
|
||||
function tap($formulas)
|
||||
{
|
||||
$formulas = is_array($formulas) ? $formulas : func_get_args();
|
||||
|
||||
foreach ($formulas as $formula) {
|
||||
passthru('sudo -u '.$_SERVER['SUDO_USER'].' brew tap '.$formula);
|
||||
$this->cli->passthru('sudo -u '.user().' brew tap '.$formula);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,12 +64,12 @@ public static function tap($formulas)
|
||||
*
|
||||
* @param
|
||||
*/
|
||||
public static function restartService($services)
|
||||
function restartService($services)
|
||||
{
|
||||
$services = is_array($services) ? $services : func_get_args();
|
||||
|
||||
foreach ($services as $service) {
|
||||
quietly('sudo brew services restart '.$service);
|
||||
$this->cli->quietly('sudo brew services restart '.$service);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,12 +78,12 @@ public static function restartService($services)
|
||||
*
|
||||
* @param
|
||||
*/
|
||||
public static function stopService($services)
|
||||
function stopService($services)
|
||||
{
|
||||
$services = is_array($services) ? $services : func_get_args();
|
||||
|
||||
foreach ($services as $service) {
|
||||
quietly('sudo brew services stop '.$service);
|
||||
$this->cli->quietly('sudo brew services stop '.$service);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,20 +92,20 @@ public static function stopService($services)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function linkedPhp()
|
||||
function linkedPhp()
|
||||
{
|
||||
if (! is_link('/usr/local/bin/php')) {
|
||||
throw new Exception("Unable to determine linked PHP.");
|
||||
if (! $this->files->isLink('/usr/local/bin/php')) {
|
||||
throw new DomainException("Unable to determine linked PHP.");
|
||||
}
|
||||
|
||||
$resolvedPath = readlink('/usr/local/bin/php');
|
||||
$resolvedPath = $this->files->readLink('/usr/local/bin/php');
|
||||
|
||||
if (strpos($resolvedPath, 'php70') !== false) {
|
||||
return 'php70';
|
||||
} elseif (strpos($resolvedPath, 'php56') !== false) {
|
||||
return 'php56';
|
||||
} else {
|
||||
throw new Exception("Unable to determine linked PHP.");
|
||||
throw new DomainException("Unable to determine linked PHP.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +114,8 @@ public static function linkedPhp()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function restartLinkedPhp()
|
||||
function restartLinkedPhp()
|
||||
{
|
||||
return static::restartService(static::linkedPhp());
|
||||
return $this->restartService($this->linkedPhp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,37 +4,81 @@
|
||||
|
||||
class Caddy
|
||||
{
|
||||
var $cli;
|
||||
var $files;
|
||||
var $daemonPath = '/Library/LaunchDaemons/com.laravel.valetServer.plist';
|
||||
|
||||
/**
|
||||
* Install the system launch daemon for the Node proxy.
|
||||
* Create a new Brew instance.
|
||||
*
|
||||
* @param CommandLine $cli
|
||||
* @param Filesystem $files
|
||||
* @return void
|
||||
*/
|
||||
function __construct(CommandLine $cli, Filesystem $files)
|
||||
{
|
||||
$this->cli = $cli;
|
||||
$this->files = $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the system launch daemon for the Caddy server.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function install()
|
||||
function install()
|
||||
{
|
||||
file_put_contents(
|
||||
VALET_HOME_PATH.'/Caddyfile',
|
||||
str_replace('USER', $_SERVER['SUDO_USER'], file_get_contents(__DIR__.'/../stubs/Caddyfile'))
|
||||
);
|
||||
|
||||
chown(VALET_HOME_PATH.'/Caddyfile', $_SERVER['SUDO_USER']);
|
||||
|
||||
if (! is_dir($caddyDirectory = VALET_HOME_PATH.'/Caddy')) {
|
||||
mkdir($caddyDirectory, 0755);
|
||||
|
||||
chown($caddyDirectory, $_SERVER['SUDO_USER']);
|
||||
$this->installCaddyFile();
|
||||
$this->installCaddyDirectory();
|
||||
$this->installCaddyDaemon();
|
||||
}
|
||||
|
||||
touch($caddyDirectory.'/.keep');
|
||||
/**
|
||||
* Install the Caddyfile to the ~/.valet directory.
|
||||
*
|
||||
* This file serves as the main server configuration for Valet.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function installCaddyFile()
|
||||
{
|
||||
$this->files->putAsUser(
|
||||
VALET_HOME_PATH.'/Caddyfile',
|
||||
str_replace('USER', user(), $this->files->get(__DIR__.'/../stubs/Caddyfile'))
|
||||
);
|
||||
}
|
||||
|
||||
chown($caddyDirectory.'/.keep', $_SERVER['SUDO_USER']);
|
||||
/**
|
||||
* Install the Caddy configuration directory to the ~/.valet directory.
|
||||
*
|
||||
* This directory contains all site-specific Caddy definitions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function installCaddyDirectory()
|
||||
{
|
||||
if (! $this->files->isDir($caddyDirectory = VALET_HOME_PATH.'/Caddy')) {
|
||||
$this->files->mkdirAsUser($caddyDirectory);
|
||||
}
|
||||
|
||||
$this->files->touchAsUser($caddyDirectory.'/.keep');
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the Caddy daemon on a system level daemon.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function installCaddyDaemon()
|
||||
{
|
||||
$contents = str_replace(
|
||||
'VALET_PATH', realpath(__DIR__.'/../'), file_get_contents(__DIR__.'/../stubs/daemon.plist')
|
||||
'VALET_PATH', $this->files->realpath(__DIR__.'/../'),
|
||||
$this->files->get(__DIR__.'/../stubs/daemon.plist')
|
||||
);
|
||||
|
||||
$contents = str_replace('VALET_HOME_PATH', VALET_HOME_PATH, $contents);
|
||||
|
||||
file_put_contents('/Library/LaunchDaemons/com.laravel.valetServer.plist', $contents);
|
||||
$this->files->put(
|
||||
$this->daemonPath, str_replace('VALET_HOME_PATH', VALET_HOME_PATH, $contents)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,11 +86,11 @@ public static function install()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function restart()
|
||||
function restart()
|
||||
{
|
||||
quietly('launchctl unload /Library/LaunchDaemons/com.laravel.valetServer.plist > /dev/null');
|
||||
$this->cli->quietly('launchctl unload '.$this->daemonPath);
|
||||
|
||||
exec('launchctl load /Library/LaunchDaemons/com.laravel.valetServer.plist');
|
||||
$this->cli->quietly('launchctl load '.$this->daemonPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,9 +98,9 @@ public static function restart()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function stop()
|
||||
function stop()
|
||||
{
|
||||
quietly('launchctl unload /Library/LaunchDaemons/com.laravel.valetServer.plist > /dev/null');
|
||||
$this->cli->quietly('launchctl unload '.$this->daemonPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,10 +108,10 @@ public static function stop()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall()
|
||||
function uninstall()
|
||||
{
|
||||
static::stop();
|
||||
$this->stop();
|
||||
|
||||
unlink('/Library/LaunchDaemons/com.laravel.valetServer.plist');
|
||||
$this->files->unlink($this->daemonPath);
|
||||
}
|
||||
}
|
||||
|
||||
64
src/CommandLine.php
Normal file
64
src/CommandLine.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Valet;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class CommandLine
|
||||
{
|
||||
/**
|
||||
* Simple global function to run commands.
|
||||
*/
|
||||
public function quietly($command)
|
||||
{
|
||||
(new Process($command))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the command to the command line and display the output.
|
||||
*
|
||||
* @param string $command
|
||||
* @return void
|
||||
*/
|
||||
public function passthru($command)
|
||||
{
|
||||
passthru($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given command.
|
||||
*
|
||||
* @param string $command
|
||||
* @param callable $onError
|
||||
* @return string
|
||||
*/
|
||||
public function run($command, callable $onError = null)
|
||||
{
|
||||
return $this->runAsRoot('sudo -u '.$_SERVER['SUDO_USER'].' '.$command, $onError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given command as root.
|
||||
*
|
||||
* @param string $command
|
||||
* @param callable $onError
|
||||
* @return string
|
||||
*/
|
||||
public function runAsRoot($command, callable $onError = null)
|
||||
{
|
||||
$onError = $onError ?: function () {};
|
||||
|
||||
$process = new Process($command);
|
||||
|
||||
$processOutput = '';
|
||||
$process->run(function ($type, $line) use (&$processOutput) {
|
||||
$processOutput .= $line;
|
||||
});
|
||||
|
||||
if ($process->getExitCode() > 0) {
|
||||
$onError($process->getExitCode(), $processOutput);
|
||||
}
|
||||
|
||||
return $processOutput;
|
||||
}
|
||||
}
|
||||
@@ -4,33 +4,85 @@
|
||||
|
||||
class Configuration
|
||||
{
|
||||
var $files;
|
||||
|
||||
/**
|
||||
* Create a new Valet configuration class instance.
|
||||
*
|
||||
* @param Filesystem $filesystem
|
||||
* @return void
|
||||
*/
|
||||
function __construct(Filesystem $files)
|
||||
{
|
||||
$this->files = $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the Valet configuration file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function install()
|
||||
function install()
|
||||
{
|
||||
if (! is_dir($directory = VALET_HOME_PATH)) {
|
||||
mkdir($directory, 0755);
|
||||
$this->createConfigurationDirectory();
|
||||
$this->createDriversDirectory();
|
||||
$this->writeBaseConfiguration();
|
||||
|
||||
chown($directory, $_SERVER['SUDO_USER']);
|
||||
$this->files->chown($this->path(), user());
|
||||
}
|
||||
|
||||
if (! is_dir($driversDirectory = VALET_HOME_PATH.'/Drivers')) {
|
||||
mkdir($driversDirectory, 0755);
|
||||
|
||||
copy(__DIR__.'/../stubs/SampleValetDriver.php', $driversDirectory.'/SampleValetDriver.php');
|
||||
|
||||
chown($driversDirectory.'/SampleValetDriver.php', $_SERVER['SUDO_USER']);
|
||||
chown($driversDirectory, $_SERVER['SUDO_USER']);
|
||||
/**
|
||||
* Create the Valet configuration directory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function createConfigurationDirectory()
|
||||
{
|
||||
if (! $this->files->isDir(VALET_HOME_PATH)) {
|
||||
$this->files->mkdirAsUser(VALET_HOME_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
if (! file_exists(static::path())) {
|
||||
static::write(['domain' => 'dev', 'paths' => []]);
|
||||
/**
|
||||
* Create the Valet drivers directory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function createDriversDirectory()
|
||||
{
|
||||
if ($this->files->isDir($driversDirectory = VALET_HOME_PATH.'/Drivers')) {
|
||||
return;
|
||||
}
|
||||
|
||||
chown(static::path(), $_SERVER['SUDO_USER']);
|
||||
$this->files->mkdirAsUser($driversDirectory);
|
||||
|
||||
$this->files->putAsUser(
|
||||
$driversDirectory.'/SampleValetDriver.php',
|
||||
$this->files->get(__DIR__.'/../stubs/SampleValetDriver.php')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the base, initial configuration for Valet.
|
||||
*/
|
||||
function writeBaseConfiguration()
|
||||
{
|
||||
if (! $this->files->exists($this->path())) {
|
||||
$this->write(['domain' => 'dev', 'paths' => []]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given path to the configuration.
|
||||
*
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
function addPath($path)
|
||||
{
|
||||
$this->write(tap($this->read(), function (&$config) use ($path) {
|
||||
$config['paths'] = collect($config['paths'])->push($path)->unique()->all();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,44 +91,13 @@ public static function install()
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public static function addPath($path)
|
||||
function removePath($path)
|
||||
{
|
||||
$config = static::read();
|
||||
|
||||
$config['paths'] = array_unique(array_merge($config['paths'], [$path]));
|
||||
|
||||
static::write($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given path to the configuration.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public static function removePath($path)
|
||||
{
|
||||
$config = static::read();
|
||||
|
||||
foreach ($config['paths'] as $key => $value) {
|
||||
if ($path === $value) {
|
||||
unset($config['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$config['paths'] = array_unique(array_values($config['paths']));
|
||||
|
||||
static::write($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration file path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function path()
|
||||
{
|
||||
return VALET_HOME_PATH.'/config.json';
|
||||
$this->write(tap($this->read(), function (&$config) use ($path) {
|
||||
$config['paths'] = collect($config['paths'])->reject(function ($value) use ($path) {
|
||||
return $value === $path;
|
||||
})->values()->all();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,23 +105,17 @@ public static function path()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function prune()
|
||||
function prune()
|
||||
{
|
||||
if (! file_exists(static::path())) {
|
||||
if (! $this->files->exists($this->path())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = static::read();
|
||||
|
||||
foreach ($config['paths'] as $key => $path) {
|
||||
if (! is_dir($path)) {
|
||||
unset($config['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$config['paths'] = array_values($config['paths']);
|
||||
|
||||
static::write($config);
|
||||
$this->write(tap($this->read(), function (&$config) {
|
||||
$config['paths'] = collect($config['paths'])->filter(function ($path) {
|
||||
return $this->files->isDir($path);
|
||||
})->values()->all();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,9 +123,9 @@ public static function prune()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function read()
|
||||
function read()
|
||||
{
|
||||
return json_decode(file_get_contents(static::path()), true);
|
||||
return json_decode($this->files->get($this->path()), true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,15 +135,13 @@ public static function read()
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public static function updateKey($key, $value)
|
||||
function updateKey($key, $value)
|
||||
{
|
||||
$config = static::read();
|
||||
|
||||
return tap($this->read(), function (&$config) use ($key, $value) {
|
||||
$config[$key] = $value;
|
||||
|
||||
static::write($config);
|
||||
|
||||
return $config;
|
||||
$this->write($config);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,8 +150,20 @@ public static function updateKey($key, $value)
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public static function write(array $config)
|
||||
function write(array $config)
|
||||
{
|
||||
file_put_contents(static::path(), json_encode($config, JSON_PRETTY_PRINT).PHP_EOL);
|
||||
$this->files->putAsUser($this->path(), json_encode(
|
||||
$config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
|
||||
).PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration file path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function path()
|
||||
{
|
||||
return VALET_HOME_PATH.'/config.json';
|
||||
}
|
||||
}
|
||||
|
||||
190
src/Filesystem.php
Normal file
190
src/Filesystem.php
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace Valet;
|
||||
|
||||
class Filesystem
|
||||
{
|
||||
/**
|
||||
* Determine if the given path is a directory.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public function isDir($path)
|
||||
{
|
||||
return is_dir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string|null $owner
|
||||
* @param int $mode
|
||||
* @return void
|
||||
*/
|
||||
public function mkdir($path, $owner = null, $mode = 0755)
|
||||
{
|
||||
mkdir($path, $mode);
|
||||
|
||||
if ($owner) {
|
||||
$this->chown($path, $owner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory as the non-root user.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $mode
|
||||
* @return void
|
||||
*/
|
||||
public function mkdirAsUser($path, $mode = 0755)
|
||||
{
|
||||
return $this->mkdir($path, user(), $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Touch the given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string|null $owner
|
||||
* @return void
|
||||
*/
|
||||
public function touch($path, $owner = null)
|
||||
{
|
||||
touch($path);
|
||||
|
||||
if ($owner) {
|
||||
$this->chown($path, $owner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Touch the given path as the non-root user.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function touchAsUser($path)
|
||||
{
|
||||
return $this->touch($path, user());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given file exists.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($path)
|
||||
{
|
||||
return file_exists($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the contents of the given file.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function get($path)
|
||||
{
|
||||
return file_get_contents($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to the given file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $contents
|
||||
* @param string|null $owner
|
||||
* @return string
|
||||
*/
|
||||
public function put($path, $contents, $owner = null)
|
||||
{
|
||||
file_put_contents($path, $contents);
|
||||
|
||||
if ($owner) {
|
||||
$this->chown($path, $owner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to the given file as the non-root user.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $contents
|
||||
* @return string
|
||||
*/
|
||||
public function putAsUser($path, $contents)
|
||||
{
|
||||
return $this->put($path, $contents, user());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the file at the given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function unlink($path)
|
||||
{
|
||||
@unlink($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the owner of the given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $user
|
||||
*/
|
||||
public function chown($path, $user)
|
||||
{
|
||||
chown($path, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the group of the given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $group
|
||||
*/
|
||||
public function chgrp($path, $group)
|
||||
{
|
||||
chgrp($path, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function realpath($path)
|
||||
{
|
||||
return realpath($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given path is a symbolic link.
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public function isLink($path)
|
||||
{
|
||||
return is_link($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given symbolic link.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function readLink($path)
|
||||
{
|
||||
return read_link($path);
|
||||
}
|
||||
}
|
||||
152
tests/BrewTest.php
Normal file
152
tests/BrewTest.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
use Valet\Brew;
|
||||
use Valet\Filesystem;
|
||||
use Valet\CommandLine;
|
||||
use Illuminate\Container\Container;
|
||||
|
||||
class BrewTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$_SERVER['SUDO_USER'] = 'Taylor';
|
||||
|
||||
Container::setInstance(new Container);
|
||||
}
|
||||
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
Mockery::close();
|
||||
}
|
||||
|
||||
|
||||
public function test_brew_can_be_resolved_from_container()
|
||||
{
|
||||
$this->assertInstanceOf(Brew::class, resolve(Brew::class));
|
||||
}
|
||||
|
||||
|
||||
public function test_installed_returns_true_when_given_formula_is_installed()
|
||||
{
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('run')->with('brew list | grep php70')->andReturn('php70');
|
||||
swap(CommandLine::class, $cli);
|
||||
$this->assertTrue(resolve(Brew::class)->installed('php70'));
|
||||
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('run')->with('brew list | grep php70')->andReturn('php70-mcrypt
|
||||
php70');
|
||||
swap(CommandLine::class, $cli);
|
||||
$this->assertTrue(resolve(Brew::class)->installed('php70'));
|
||||
}
|
||||
|
||||
|
||||
public function test_installed_returns_false_when_given_formula_is_not_installed()
|
||||
{
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('run')->with('brew list | grep php70')->andReturn('');
|
||||
swap(CommandLine::class, $cli);
|
||||
$this->assertFalse(resolve(Brew::class)->installed('php70'));
|
||||
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('run')->with('brew list | grep php70')->andReturn('php70-mcrypt');
|
||||
swap(CommandLine::class, $cli);
|
||||
$this->assertFalse(resolve(Brew::class)->installed('php70'));
|
||||
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('run')->with('brew list | grep php70')->andReturn('php70-mcrypt
|
||||
php70-something-else
|
||||
php7');
|
||||
swap(CommandLine::class, $cli);
|
||||
$this->assertFalse(resolve(Brew::class)->installed('php70'));
|
||||
}
|
||||
|
||||
|
||||
public function test_has_installed_php_indicates_if_php_is_installed_via_brew()
|
||||
{
|
||||
$brew = Mockery::mock(Brew::class.'[installed]', [new CommandLine, new Filesystem]);
|
||||
$brew->shouldReceive('installed')->with('php70')->andReturn(true);
|
||||
$brew->shouldReceive('installed')->with('php56')->andReturn(true);
|
||||
$this->assertTrue($brew->hasInstalledPhp());
|
||||
|
||||
$brew = Mockery::mock(Brew::class.'[installed]', [new CommandLine, new Filesystem]);
|
||||
$brew->shouldReceive('installed')->with('php70')->andReturn(true);
|
||||
$brew->shouldReceive('installed')->with('php56')->andReturn(false);
|
||||
$this->assertTrue($brew->hasInstalledPhp());
|
||||
|
||||
$brew = Mockery::mock(Brew::class.'[installed]', [new CommandLine, new Filesystem]);
|
||||
$brew->shouldReceive('installed')->with('php70')->andReturn(false);
|
||||
$brew->shouldReceive('installed')->with('php56')->andReturn(false);
|
||||
$this->assertFalse($brew->hasInstalledPhp());
|
||||
}
|
||||
|
||||
|
||||
public function test_tap_taps_the_given_homebrew_repository()
|
||||
{
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('passthru')->with('sudo -u Taylor brew tap php70');
|
||||
$cli->shouldReceive('passthru')->with('sudo -u Taylor brew tap php56');
|
||||
swap(CommandLine::class, $cli);
|
||||
resolve(Brew::class)->tap('php70', 'php56');
|
||||
}
|
||||
|
||||
|
||||
public function test_restart_restarts_the_service_using_homebrew_services()
|
||||
{
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('quietly')->with('sudo brew services restart dnsmasq');
|
||||
swap(CommandLine::class, $cli);
|
||||
resolve(Brew::class)->restartService('dnsmasq');
|
||||
}
|
||||
|
||||
|
||||
public function test_stop_stops_the_service_using_homebrew_services()
|
||||
{
|
||||
$cli = Mockery::mock(CommandLine::class);
|
||||
$cli->shouldReceive('quietly')->with('sudo brew services stop dnsmasq');
|
||||
swap(CommandLine::class, $cli);
|
||||
resolve(Brew::class)->stopService('dnsmasq');
|
||||
}
|
||||
|
||||
|
||||
public function test_linked_php_returns_linked_php_formula_name()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isLink')->with('/usr/local/bin/php')->andReturn(true);
|
||||
$files->shouldReceive('readLink')->with('/usr/local/bin/php')->andReturn('/test/path/php70/test');
|
||||
swap(Filesystem::class, $files);
|
||||
$this->assertEquals('php70', resolve(Brew::class)->linkedPhp());
|
||||
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isLink')->with('/usr/local/bin/php')->andReturn(true);
|
||||
$files->shouldReceive('readLink')->with('/usr/local/bin/php')->andReturn('/test/path/php56/test');
|
||||
swap(Filesystem::class, $files);
|
||||
$this->assertEquals('php56', resolve(Brew::class)->linkedPhp());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @expectedException DomainException
|
||||
*/
|
||||
public function test_linked_php_throws_exception_if_no_php_link()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isLink')->with('/usr/local/bin/php')->andReturn(false);
|
||||
swap(Filesystem::class, $files);
|
||||
resolve(Brew::class)->linkedPhp();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @expectedException DomainException
|
||||
*/
|
||||
public function test_linked_php_throws_exception_if_unsupported_php_version_is_linked()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isLink')->with('/usr/local/bin/php')->andReturn(true);
|
||||
$files->shouldReceive('readLink')->with('/usr/local/bin/php')->andReturn('/test/path/php42/test');
|
||||
swap(Filesystem::class, $files);
|
||||
resolve(Brew::class)->linkedPhp();
|
||||
}
|
||||
}
|
||||
81
tests/CaddyTest.php
Normal file
81
tests/CaddyTest.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
use Valet\Caddy;
|
||||
use Valet\Filesystem;
|
||||
use Valet\CommandLine;
|
||||
use Illuminate\Container\Container;
|
||||
|
||||
class CaddyTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$_SERVER['SUDO_USER'] = 'Taylor';
|
||||
|
||||
Container::setInstance(new Container);
|
||||
}
|
||||
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
Mockery::close();
|
||||
}
|
||||
|
||||
|
||||
public function test_install_caddy_file_places_stub_in_valet_home_directory()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class.'[putAsUser]');
|
||||
|
||||
$files->shouldReceive('putAsUser')->andReturnUsing(function ($path, $contents) {
|
||||
$this->assertEquals(VALET_HOME_PATH.'/Caddyfile', $path);
|
||||
$this->assertTrue(strpos($contents, 'import /Users/'.user().'/.valet/Caddy/*') !== false);
|
||||
});
|
||||
|
||||
swap(Filesystem::class, $files);
|
||||
$caddy = resolve(Caddy::class);
|
||||
$caddy->installCaddyFile();
|
||||
}
|
||||
|
||||
|
||||
public function test_install_caddy_directories_creates_location_for_site_specific_configuration()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Caddy')->andReturn(false);
|
||||
$files->shouldReceive('mkdirAsUser')->with(VALET_HOME_PATH.'/Caddy');
|
||||
$files->shouldReceive('touchAsUser')->with(VALET_HOME_PATH.'/Caddy/.keep');
|
||||
|
||||
swap(Filesystem::class, $files);
|
||||
$caddy = resolve(Caddy::class);
|
||||
|
||||
$caddy->installCaddyDirectory();
|
||||
}
|
||||
|
||||
|
||||
public function test_caddy_directory_is_never_created_if_it_already_exists()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Caddy')->andReturn(true);
|
||||
$files->shouldReceive('mkdirAsUser')->never();
|
||||
$files->shouldReceive('touchAsUser')->with(VALET_HOME_PATH.'/Caddy/.keep');
|
||||
|
||||
swap(Filesystem::class, $files);
|
||||
$caddy = resolve(Caddy::class);
|
||||
|
||||
$caddy->installCaddyDirectory();
|
||||
}
|
||||
|
||||
|
||||
public function test_caddy_daemon_is_placed_in_correct_location()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class.'[put]');
|
||||
|
||||
swap(Filesystem::class, $files);
|
||||
$caddy = resolve(Caddy::class);
|
||||
|
||||
$files->shouldReceive('put')->andReturnUsing(function ($path, $contents) use ($caddy) {
|
||||
$this->assertEquals($caddy->daemonPath, $path);
|
||||
$this->assertTrue(strpos($contents, VALET_HOME_PATH) !== false);
|
||||
});
|
||||
|
||||
$caddy->installCaddyDaemon();
|
||||
}
|
||||
}
|
||||
122
tests/ConfigurationTest.php
Normal file
122
tests/ConfigurationTest.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
use Valet\Filesystem;
|
||||
use Valet\Configuration;
|
||||
use Illuminate\Container\Container;
|
||||
|
||||
class ConfigurationTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$_SERVER['SUDO_USER'] = 'Taylor';
|
||||
|
||||
Container::setInstance(new Container);
|
||||
}
|
||||
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
Mockery::close();
|
||||
}
|
||||
|
||||
|
||||
public function test_configuration_directory_is_created_if_it_doesnt_exist()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isDir')->with(VALET_HOME_PATH)->andReturn(false);
|
||||
$files->shouldReceive('mkdirAsUser')->with(VALET_HOME_PATH);
|
||||
swap(Filesystem::class, $files);
|
||||
resolve(Configuration::class)->createConfigurationDirectory();
|
||||
|
||||
$files = Mockery::mock(Filesystem::class);
|
||||
$files->shouldReceive('isDir')->with(VALET_HOME_PATH)->andReturn(true);
|
||||
$files->shouldReceive('mkdirAsUser')->never();
|
||||
swap(Filesystem::class, $files);
|
||||
resolve(Configuration::class)->createConfigurationDirectory();
|
||||
}
|
||||
|
||||
|
||||
public function test_drivers_directory_is_created_with_sample_driver_if_it_doesnt_exist()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class.'[isDir,mkdirAsUser,putAsUser]');
|
||||
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Drivers')->andReturn(false);
|
||||
$files->shouldReceive('mkdirAsUser')->with(VALET_HOME_PATH.'/Drivers');
|
||||
$files->shouldReceive('putAsUser');
|
||||
swap(Filesystem::class, $files);
|
||||
resolve(Configuration::class)->createDriversDirectory();
|
||||
}
|
||||
|
||||
|
||||
public function test_add_path_adds_a_path_to_the_paths_array_and_removes_duplicates()
|
||||
{
|
||||
$config = Mockery::mock(Configuration::class.'[read,write]', [new Filesystem]);
|
||||
$config->shouldReceive('read')->andReturn([
|
||||
'paths' => ['path-1', 'path-2'],
|
||||
]);
|
||||
$config->shouldReceive('write')->with([
|
||||
'paths' => ['path-1', 'path-2', 'path-3'],
|
||||
]);
|
||||
$config->addPath('path-3');
|
||||
|
||||
$config = Mockery::mock(Configuration::class.'[read,write]', [new Filesystem]);
|
||||
$config->shouldReceive('read')->andReturn([
|
||||
'paths' => ['path-1', 'path-2', 'path-3'],
|
||||
]);
|
||||
$config->shouldReceive('write')->with([
|
||||
'paths' => ['path-1', 'path-2', 'path-3'],
|
||||
]);
|
||||
$config->addPath('path-3');
|
||||
}
|
||||
|
||||
|
||||
public function test_paths_may_be_removed_from_the_configuration()
|
||||
{
|
||||
$config = Mockery::mock(Configuration::class.'[read,write]', [new Filesystem]);
|
||||
$config->shouldReceive('read')->andReturn([
|
||||
'paths' => ['path-1', 'path-2'],
|
||||
]);
|
||||
$config->shouldReceive('write')->with([
|
||||
'paths' => ['path-1'],
|
||||
]);
|
||||
$config->removePath('path-2');
|
||||
}
|
||||
|
||||
|
||||
public function test_prune_removes_directories_from_paths_that_no_longer_exist()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class.'[exists,isDir]');
|
||||
swap(Filesystem::class, $files);
|
||||
$files->shouldReceive('exists')->with(VALET_HOME_PATH.'/config.json')->andReturn(true);
|
||||
$files->shouldReceive('isDir')->with('path-1')->andReturn(true);
|
||||
$files->shouldReceive('isDir')->with('path-2')->andReturn(false);
|
||||
$config = Mockery::mock(Configuration::class.'[read,write]', [$files]);
|
||||
$config->shouldReceive('read')->andReturn([
|
||||
'paths' => ['path-1', 'path-2'],
|
||||
]);
|
||||
$config->shouldReceive('write')->with([
|
||||
'paths' => ['path-1'],
|
||||
]);
|
||||
$config->prune();
|
||||
}
|
||||
|
||||
|
||||
public function test_prune_doesnt_execute_if_configuration_directory_doesnt_exist()
|
||||
{
|
||||
$files = Mockery::mock(Filesystem::class.'[exists]');
|
||||
swap(Filesystem::class, $files);
|
||||
$files->shouldReceive('exists')->with(VALET_HOME_PATH.'/config.json')->andReturn(false);
|
||||
$config = Mockery::mock(Configuration::class.'[read,write]', [$files]);
|
||||
$config->shouldReceive('read')->never();
|
||||
$config->shouldReceive('write')->never();
|
||||
$config->prune();
|
||||
}
|
||||
|
||||
|
||||
public function test_update_key_updates_the_specified_configuration_key()
|
||||
{
|
||||
$config = Mockery::mock(Configuration::class.'[read,write]', [new Filesystem]);
|
||||
$config->shouldReceive('read')->once()->andReturn(['foo' => 'bar']);
|
||||
$config->shouldReceive('write')->once()->with(['foo' => 'bar', 'bar' => 'baz']);
|
||||
$config->updateKey('bar', 'baz');
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,13 @@
|
||||
}
|
||||
|
||||
use Silly\Application;
|
||||
use Illuminate\Container\Container;
|
||||
|
||||
/**
|
||||
* Create the application.
|
||||
*/
|
||||
Container::setInstance(new Container);
|
||||
|
||||
$app = new Application('Laravel Valet', 'v1.0.12');
|
||||
|
||||
/**
|
||||
@@ -44,7 +47,7 @@
|
||||
|
||||
Valet\Caddy::restart();
|
||||
|
||||
$output->writeln(PHP_EOL.'<info>Valet installed successfully!</info>');
|
||||
output(PHP_EOL.'<info>Valet installed successfully!</info>');
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user