From 37b4af4113078cbf821169fa26affa2ca3ade004 Mon Sep 17 00:00:00 2001 From: NasirNobin Date: Sun, 6 Feb 2022 13:56:35 +0600 Subject: [PATCH 01/41] Multiple/Parallel PHP Version Support for Valet --- cli/Valet/Nginx.php | 19 +---- cli/Valet/PhpFpm.php | 157 +++++++++++++++++++++++++++++++------- cli/Valet/Site.php | 121 ++++++++++++++++++++++++++++- cli/stubs/site.valet.conf | 40 ++++++++++ cli/valet.php | 27 +++++-- tests/PhpFpmTest.php | 3 +- 6 files changed, 313 insertions(+), 54 deletions(-) create mode 100644 cli/stubs/site.valet.conf diff --git a/cli/Valet/Nginx.php b/cli/Valet/Nginx.php index 8f84c014d..0ab30d4cd 100644 --- a/cli/Valet/Nginx.php +++ b/cli/Valet/Nginx.php @@ -80,7 +80,7 @@ public function installServer() str_replace( ['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX'], [VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX], - $this->replaceLoopback($this->files->get(__DIR__.'/../stubs/valet.conf')) + $this->site->replaceLoopback($this->files->get(__DIR__.'/../stubs/valet.conf')) ) ); @@ -90,23 +90,6 @@ public function installServer() ); } - public function replaceLoopback($siteConf) - { - $loopback = $this->configuration->read()['loopback']; - - if ($loopback === VALET_LOOPBACK) { - return $siteConf; - } - - $str = '#listen VALET_LOOPBACK:80; # valet loopback'; - - return str_replace( - $str, - substr(str_replace('VALET_LOOPBACK', $loopback, $str), 1), - $siteConf - ); - } - /** * Install the Nginx configuration directory to the ~/.config/valet directory. * diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index bfe7c7b45..b28ae6c58 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -33,9 +33,10 @@ public function __construct(Brew $brew, CommandLine $cli, Filesystem $files) /** * Install and configure PhpFpm. * + * @param null $phpVersion * @return void */ - public function install() + public function install($phpVersion = null) { if (! $this->brew->hasInstalledPhp()) { $this->brew->ensureInstalled('php', [], $this->taps); @@ -43,9 +44,9 @@ public function install() $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); - $this->updateConfiguration(); + $this->updateConfiguration($phpVersion); - $this->restart(); + $this->restart($phpVersion); } /** @@ -63,13 +64,14 @@ public function uninstall() /** * Update the PHP FPM configuration. * + * @param null $phpVersion * @return void */ - public function updateConfiguration() + public function updateConfiguration($phpVersion = null) { - info('Updating PHP configuration...'); + info(sprintf('Updating PHP configuration%s...', $phpVersion ? ' for '.$phpVersion : '')); - $fpmConfigFile = $this->fpmConfigPath(); + $fpmConfigFile = $this->fpmConfigPath($phpVersion); $this->files->ensureDirExists(dirname($fpmConfigFile), user()); @@ -93,6 +95,11 @@ public function updateConfiguration() $contents = preg_replace('/^;?listen\.group = .+$/m', 'listen.group = staff', $contents); $contents = preg_replace('/^;?listen\.mode = .+$/m', 'listen.mode = 0777', $contents); } + + if ($phpVersion) { + $contents = str_replace('valet.sock', $this->fpmSockName($phpVersion), $contents); + } + $this->files->put($fpmConfigFile, $contents); $contents = $this->files->get(__DIR__.'/../stubs/php-memory-limits.ini'); @@ -118,9 +125,9 @@ public function updateConfiguration() * * @return void */ - public function restart() + public function restart($phpVersion = null) { - $this->brew->restartLinkedPhp(); + $this->brew->restartService($phpVersion ?: $this->getPhpVersionsToPerformRestart()); } /** @@ -141,11 +148,13 @@ public function stop() * * @return string */ - public function fpmConfigPath() + public function fpmConfigPath($phpVersion = null) { - $version = $this->brew->linkedPhp(); + if (! $phpVersion) { + $phpVersion = $this->brew->linkedPhp(); + } - $versionNormalized = $this->normalizePhpVersion($version === 'php' ? Brew::LATEST_PHP_VERSION : $version); + $versionNormalized = $this->normalizePhpVersion($phpVersion === 'php' ? Brew::LATEST_PHP_VERSION : $phpVersion); $versionNormalized = preg_replace('~[^\d\.]~', '', $versionNormalized); return $versionNormalized === '5.6' @@ -171,10 +180,11 @@ public function stopRunning() * Use a specific version of php. * * @param $version - * @param $force + * @param bool $force + * @param null $site * @return string */ - public function useVersion($version, $force = false) + public function useVersion($version, $force = false, $site = null) { $version = $this->validateRequestedVersion($version); @@ -192,24 +202,40 @@ public function useVersion($version, $force = false) $this->brew->ensureInstalled($version, [], $this->taps); } - // Unlink the current php if there is one - if ($this->brew->hasLinkedPhp()) { - $currentVersion = $this->brew->getLinkedPhpFormula(); - info(sprintf('Unlinking current version: %s', $currentVersion)); - $this->brew->unlink($currentVersion); - } + // we need to unlink and link only for global php version change + if ($site) { + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($version)); + $this->install($version); + } else { + // Unlink the current php if there is one + if ($this->brew->hasLinkedPhp()) { + $linkedPhp = $this->brew->linkedPhp(); + + // updating old fpm to use a custom sock + // so exising lokced php versioned sites doesn't mess up + $this->updateConfiguration($linkedPhp); + + // check all custom nginx config files + // look for the php version and update config files accordingly + $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); - info(sprintf('Linking new version: %s', $version)); - $this->brew->link($version, true); + $currentVersion = $this->brew->getLinkedPhpFormula(); + info(sprintf('Unlinking current version: %s', $currentVersion)); + $this->brew->unlink($currentVersion); + } + + info(sprintf('Linking new version: %s', $version)); + $this->brew->link($version, true); - $this->stopRunning(); + $this->stopRunning(); - // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts - $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet.sock'); + // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts + $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); - // ensure configuration is correct and start the linked version - $this->install(); + // ensure configuration is correct and start the linked version + $this->install(); + } return $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; } @@ -257,4 +283,81 @@ public function validateRequestedVersion($version) return $version; } + + /** + * Get fpm sock file name from a given php version. + * + * @param string|null $phpVersion + * @return string + */ + public function fpmSockName($phpVersion = null) + { + $versionInteger = preg_replace('~[^\d]~', '', $phpVersion); + + return "valet{$versionInteger}.sock"; + } + + /** + * Preseve exising isolated PHP versioned sites, when running a gloabl php version update. Look for the php version and will adjust that custom nginx config. + * + * @param $newPhpVersion + * @param $oldPhpVersion + */ + public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersion) + { + collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) + ->filter(function ($file) { + return ! starts_with($file, '.'); + }) + ->each(function ($file) use ($newPhpVersion, $oldPhpVersion) { + $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); + + if (! starts_with($content, '# Valet isolated PHP version')) { + return; + } + + if (strpos($content, $this->fpmSockName($newPhpVersion)) !== false) { + info(sprintf('Updating site %s to keep using version: %s', $file, $newPhpVersion)); + $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace($this->fpmSockName($newPhpVersion), 'valet.sock', $content)); + } elseif (strpos($content, 'valet.sock') !== false) { + info(sprintf('Updating site %s to keep using version: %s', $file, $oldPhpVersion)); + $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace('valet.sock', $this->fpmSockName($oldPhpVersion), $content)); + } + }); + } + + /** + * Get the PHP versions to perform restart. + * + * @return array + */ + public function getPhpVersionsToPerformRestart() + { + // scan through custom nginx files + // look for config file, that is using custom .sock files (example: php74.sock) + // restart all those PHP FPM though valet + // to make sure all the custom php versioned sites keep running + + $fpmSockFiles = $this->brew->supportedPhpVersions()->map(function ($version) { + return $this->fpmSockName($this->normalizePhpVersion($version)); + })->unique(); + + return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) + ->filter(function ($file) { + return ! starts_with($file, '.'); + }) + ->map(function ($file) use ($fpmSockFiles) { + $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); + + foreach ($fpmSockFiles as $sock) { + if (strpos($content, $sock) !== false) { + // find the PHP version number from .sock path + // valet74.sock will outout php74 + $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); + + return $this->normalizePhpVersion($phpVersion); // example output php@7.4 + } + } + })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->toArray(); + } } diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index b7f530be5..c9bd734d2 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -190,6 +190,20 @@ public function proxies() return $proxies; } + /** + * Determine if the provided site is parked. + * + * @param $valetSite + * @return bool + */ + public function isValidSite($valetSite) + { + // remove .tld to make the search a bit easier + $siteName = str_replace('.'.$this->config->read()['tld'], '', $valetSite); + + return $this->parked()->merge($this->links())->where('site', $siteName)->count() > 0; + } + /** * Identify whether a site is for a proxy by reading the host name from its config file. * @@ -474,6 +488,8 @@ public function secured() */ public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $caExpireInYears = 20) { + $phpVersion = $this->extractPhpVersion($url); // let's try to preserve the isolated php version here. Example output: 74 + $this->unsecure($url); $this->files->ensureDirExists($this->caPath(), user()); @@ -487,9 +503,15 @@ public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $ $this->createCa($caExpireInDate->format('%a')); $this->createCertificate($url, $certificateExpireInDays); - $this->files->putAsUser( - $this->nginxPath($url), $this->buildSecureNginxServer($url, $siteConf) - ); + $siteConf = $this->buildSecureNginxServer($url, $siteConf); + + // if user had any isolated php version, let's swap the .sock file, + // so it still uses the old php version + if ($phpVersion) { + $siteConf = $this->replaceSockFile($siteConf, "valet{$phpVersion}.sock", $phpVersion); + } + + $this->files->putAsUser($this->nginxPath($url), $siteConf); } /** @@ -665,6 +687,30 @@ public function buildSecureNginxServer($url, $siteConf = null) ); } + /** + * Build the Nginx server for the given valet site. + * + * @param string $valetSite + * @param string $fpmSockName + * @param $phpVersion + * @return void + */ + public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) + { + if ($this->files->exists($this->nginxPath($valetSite))) { + $siteConf = $this->files->get($this->nginxPath($valetSite)); + $siteConf = $this->replaceSockFile($siteConf, $fpmSockName, $phpVersion); + } else { + $siteConf = str_replace( + ['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX', 'VALET_SITE', 'VALET_PHP_FPM_SOCKET', 'VALET_ISOLATED_PHP_VERSION'], + [VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $valetSite, $fpmSockName, $phpVersion], + $this->replaceLoopback($this->files->get(__DIR__.'/../stubs/site.valet.conf')) + ); + } + + $this->files->putAsUser($this->nginxPath($valetSite), $siteConf); + } + /** * Unsecure the given URL so that it will use HTTP again. * @@ -673,6 +719,8 @@ public function buildSecureNginxServer($url, $siteConf = null) */ public function unsecure($url) { + $phpVersion = $this->extractPhpVersion($url); // let's try to preserve the isolated php version here. Example output: 74 + if ($this->files->exists($this->certificatesPath($url, 'crt'))) { $this->files->unlink($this->nginxPath($url)); @@ -688,6 +736,12 @@ public function unsecure($url) 'sudo security find-certificate -e "%s%s" -a -Z | grep SHA-1 | sudo awk \'{system("security delete-certificate -Z \'$NF\' /Library/Keychains/System.keychain")}\'', $url, '@laravel.valet' )); + + // if user had any isolated php version, let's swap the .sock file, + // so it still uses the old php version + if ($phpVersion) { + $this->installSiteConfig($url, "valet{$phpVersion}.sock", $phpVersion); + } } public function unsecureAll() @@ -964,4 +1018,65 @@ public function certificatesPath($url = null, $extension = null) return $this->valetHomePath().'/Certificates'.$url.$extension; } + + /** + * Replace Loopback. + * + * @param string $siteConf + * @return string + */ + public function replaceLoopback($siteConf) + { + $loopback = $this->config->read()['loopback']; + + if ($loopback === VALET_LOOPBACK) { + return $siteConf; + } + + $str = '#listen VALET_LOOPBACK:80; # valet loopback'; + + return str_replace( + $str, + substr(str_replace('VALET_LOOPBACK', $loopback, $str), 1), + $siteConf + ); + } + + /** + * Extract PHP version of exising nginx conifg. + * + * @param $url + * @return string|void + */ + public function extractPhpVersion($url) + { + if ($this->files->exists($this->nginxPath($url))) { + $siteConf = $this->files->get($this->nginxPath($url)); + + if (starts_with($siteConf, '# Valet isolated PHP version')) { + $firstLine = explode(PHP_EOL, $siteConf)[0]; + + return preg_replace("/[^\d]*/", '', $firstLine); + } + } + } + + /** + * Replace .sock file form a Nginx site conf. + * + * @param $siteConf + * @param $sockFile + * @param $phpVersion + * @return string + */ + public function replaceSockFile($siteConf, $sockFile, $phpVersion) + { + $siteConf = preg_replace('/valet[0-9]*.sock/', $sockFile, $siteConf); + + if (! starts_with($siteConf, '# Valet isolated PHP version')) { + $siteConf = '# Valet isolated PHP version : '.$phpVersion.PHP_EOL.$siteConf; + } + + return $siteConf; + } } diff --git a/cli/stubs/site.valet.conf b/cli/stubs/site.valet.conf new file mode 100644 index 000000000..26109aef4 --- /dev/null +++ b/cli/stubs/site.valet.conf @@ -0,0 +1,40 @@ +# Valet isolated PHP version : VALET_ISOLATED_PHP_VERSION +server { + listen 127.0.0.1:80; + server_name VALET_SITE www.VALET_SITE *.VALET_SITE; + #listen VALET_LOOPBACK:80; # valet loopback + root /; + charset utf-8; + client_max_body_size 128M; + + location /VALET_STATIC_PREFIX/ { + internal; + alias /; + try_files $uri $uri/; + } + + location / { + rewrite ^ "VALET_SERVER_PATH" last; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log "VALET_HOME_PATH/Log/nginx-error.log"; + + error_page 404 "VALET_SERVER_PATH"; + + location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass "unix:VALET_HOME_PATH/VALET_PHP_FPM_SOCKET"; + fastcgi_index "VALET_SERVER_PATH"; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME "VALET_SERVER_PATH"; + fastcgi_param PATH_INFO $fastcgi_path_info; + } + + location ~ /\.ht { + deny all; + } +} diff --git a/cli/valet.php b/cli/valet.php index aa711b470..2cd2cbf14 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -493,7 +493,7 @@ /** * Allow the user to change the version of php valet uses. */ - $app->command('use [phpVersion] [--force]', function ($phpVersion, $force) { + $app->command('use [phpVersion] [--force] [--site=]', function ($phpVersion, $force, $site) { if (! $phpVersion) { $path = getcwd().'/.valetphprc'; $linkedVersion = Brew::linkedPhp(); @@ -511,13 +511,30 @@ PhpFpm::validateRequestedVersion($phpVersion); - $newVersion = PhpFpm::useVersion($phpVersion, $force); + if ($site) { + if ($site == '.') { // allow user to use dot as current dir's site `--site=.` + $site = Site::host(getcwd()).'.'.Configuration::read()['tld']; + } - Nginx::restart(); - info(sprintf('Valet is now using %s.', $newVersion).PHP_EOL); - info('Note that you might need to run composer global update if your PHP version change affects the dependencies of global packages required by Composer.'); + if (! Site::isValidSite($site)) { + return warning(sprintf('Site %s could not be found in valet site list.', $site)); + } + + $newVersion = PhpFpm::useVersion($phpVersion, $force, $site); + + Site::installSiteConfig($site, PhpFpm::fpmSockName($phpVersion), $phpVersion); + Nginx::restart(); + + info(sprintf('The [%s] site is now using %s.', $site, $newVersion)); + } else { + $newVersion = PhpFpm::useVersion($phpVersion, $force); + Nginx::restart(); + info(sprintf('Valet is now using %s.', $newVersion).PHP_EOL); + info('Note that you might need to run composer global update if your PHP version change affects the dependencies of global packages required by Composer.'); + } })->descriptions('Change the version of PHP used by valet', [ 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', + '--site' => 'Isolate PHP version of a specific valet site. e.g: --site=site.test', ]); /** diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 4bd59e2e5..22124c9ae 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -115,6 +115,7 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal resolve(Filesystem::class), ])->makePartial(); $phpFpmMock->shouldReceive('install'); + $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate'); $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', @@ -138,7 +139,7 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal class StubForUpdatingFpmConfigFiles extends PhpFpm { - public function fpmConfigPath() + public function fpmConfigPath($phpVersion = null) { return __DIR__.'/output/fpm.conf'; } From acf190c57ca23f7dd350ebbbc413e4be18819aa9 Mon Sep 17 00:00:00 2001 From: Nasir Uddin Nobin Date: Tue, 15 Feb 2022 02:05:48 +0600 Subject: [PATCH 02/41] Apply suggestions from code review Co-authored-by: Matt Stauffer --- cli/Valet/PhpFpm.php | 47 ++++++++++++++++++++++---------------------- cli/Valet/Site.php | 22 ++++++++++----------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index b28ae6c58..9f8390a4d 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -33,7 +33,7 @@ public function __construct(Brew $brew, CommandLine $cli, Filesystem $files) /** * Install and configure PhpFpm. * - * @param null $phpVersion + * @param string|null $phpVersion * @return void */ public function install($phpVersion = null) @@ -64,7 +64,7 @@ public function uninstall() /** * Update the PHP FPM configuration. * - * @param null $phpVersion + * @param string|null $phpVersion * @return void */ public function updateConfiguration($phpVersion = null) @@ -181,7 +181,7 @@ public function stopRunning() * * @param $version * @param bool $force - * @param null $site + * @param string|null $site * @return string */ public function useVersion($version, $force = false, $site = null) @@ -202,21 +202,20 @@ public function useVersion($version, $force = false, $site = null) $this->brew->ensureInstalled($version, [], $this->taps); } - // we need to unlink and link only for global php version change + // Delete old Valet sock files, install the new version, and, if this is a global change, unlink and link PHP if ($site) { $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($version)); $this->install($version); } else { - // Unlink the current php if there is one + // Unlink the current global PHP if there is one installed if ($this->brew->hasLinkedPhp()) { $linkedPhp = $this->brew->linkedPhp(); - // updating old fpm to use a custom sock - // so exising lokced php versioned sites doesn't mess up + // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken $this->updateConfiguration($linkedPhp); - // check all custom nginx config files - // look for the php version and update config files accordingly + // Update existing custom Nginx config files; if they're using the old or new PHP version, + // update them to the new correct sock file location $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); $currentVersion = $this->brew->getLinkedPhpFormula(); @@ -285,7 +284,7 @@ public function validateRequestedVersion($version) } /** - * Get fpm sock file name from a given php version. + * Get FPM sock file name for a given PHP version. * * @param string|null $phpVersion * @return string @@ -298,16 +297,21 @@ public function fpmSockName($phpVersion = null) } /** - * Preseve exising isolated PHP versioned sites, when running a gloabl php version update. Look for the php version and will adjust that custom nginx config. + * Update all existing Nginx files when running a global PHP version update. + * If a given file is pointing to `valet.sock`, it's targeting the old global PHP version; + * update it to point to the new custom sock file for that version. + * If a given file is pointing the custom sock file for the new global version, that new + * version will now be hosted at `valet.sock`, so update the config file to point to that instead. * * @param $newPhpVersion * @param $oldPhpVersion + * @return void */ public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersion) { collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) - ->filter(function ($file) { - return ! starts_with($file, '.'); + ->reject(function ($file) { + return starts_with($file, '.'); }) ->each(function ($file) use ($newPhpVersion, $oldPhpVersion) { $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); @@ -327,32 +331,29 @@ public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersio } /** - * Get the PHP versions to perform restart. + * Get a list of all PHP versions currently serving "isolated sites" (sites with custom Nginx + * configs pointing them to a specific PHP version). * * @return array */ public function getPhpVersionsToPerformRestart() { - // scan through custom nginx files - // look for config file, that is using custom .sock files (example: php74.sock) - // restart all those PHP FPM though valet - // to make sure all the custom php versioned sites keep running - $fpmSockFiles = $this->brew->supportedPhpVersions()->map(function ($version) { return $this->fpmSockName($this->normalizePhpVersion($version)); })->unique(); return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) - ->filter(function ($file) { - return ! starts_with($file, '.'); + ->reject(function ($file) { + return starts_with($file, '.'); }) ->map(function ($file) use ($fpmSockFiles) { $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); + // Get the normalized PHP version for this config file, if it's defined foreach ($fpmSockFiles as $sock) { if (strpos($content, $sock) !== false) { - // find the PHP version number from .sock path - // valet74.sock will outout php74 + // Extract the PHP version number from a custom .sock path; + // for example, "valet74.sock" will output "php74" $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); return $this->normalizePhpVersion($phpVersion); // example output php@7.4 diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index c9bd734d2..1ee192c9a 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -191,14 +191,14 @@ public function proxies() } /** - * Determine if the provided site is parked. + * Determine if the provided site is a valid site, whether parked or linked. * - * @param $valetSite + * @param string $valetSite * @return bool */ public function isValidSite($valetSite) { - // remove .tld to make the search a bit easier + // Remove .tld from sitename if it was provided $siteName = str_replace('.'.$this->config->read()['tld'], '', $valetSite); return $this->parked()->merge($this->links())->where('site', $siteName)->count() > 0; @@ -488,7 +488,8 @@ public function secured() */ public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $caExpireInYears = 20) { - $phpVersion = $this->extractPhpVersion($url); // let's try to preserve the isolated php version here. Example output: 74 + // Extract in order to later preserve custom PHP version config when securing + $phpVersion = $this->extractPhpVersion($url); $this->unsecure($url); @@ -505,8 +506,7 @@ public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $ $siteConf = $this->buildSecureNginxServer($url, $siteConf); - // if user had any isolated php version, let's swap the .sock file, - // so it still uses the old php version + // If they user had isolated the PHP version for this site, swap out .sock file if ($phpVersion) { $siteConf = $this->replaceSockFile($siteConf, "valet{$phpVersion}.sock", $phpVersion); } @@ -1020,7 +1020,7 @@ public function certificatesPath($url = null, $extension = null) } /** - * Replace Loopback. + * Replace Loopback configuration line in Valet site configuration file contents. * * @param string $siteConf * @return string @@ -1062,11 +1062,11 @@ public function extractPhpVersion($url) } /** - * Replace .sock file form a Nginx site conf. + * Replace .sock file in an Nginx site configuration file contents. * - * @param $siteConf - * @param $sockFile - * @param $phpVersion + * @param string $siteConf + * @param string $sockFile + * @param string $phpVersion * @return string */ public function replaceSockFile($siteConf, $sockFile, $phpVersion) From c247dc97095cf56d482617632370e88b5dcd9e7b Mon Sep 17 00:00:00 2001 From: Nasir Uddin Nobin Date: Tue, 15 Feb 2022 02:38:46 +0600 Subject: [PATCH 03/41] Add Valet PHP isolation remover option & apply more suggestions from code review --- cli/Valet/PhpFpm.php | 10 ++++++---- cli/Valet/Site.php | 41 ++++++++++++++++++++++++++++++----------- cli/valet.php | 27 +++++++++++++++++++-------- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 9f8390a4d..44114b0c0 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -123,11 +123,12 @@ public function updateConfiguration($phpVersion = null) /** * Restart the PHP FPM process. * + * @param string|null $phpVersion * @return void */ public function restart($phpVersion = null) { - $this->brew->restartService($phpVersion ?: $this->getPhpVersionsToPerformRestart()); + $this->brew->restartService($phpVersion ?: $this->utilizedPhpVersions()); } /** @@ -146,6 +147,7 @@ public function stop() /** * Get the path to the FPM configuration file for the current PHP version. * + * @param string|null $phpVersion * @return string */ public function fpmConfigPath($phpVersion = null) @@ -298,7 +300,7 @@ public function fpmSockName($phpVersion = null) /** * Update all existing Nginx files when running a global PHP version update. - * If a given file is pointing to `valet.sock`, it's targeting the old global PHP version; + * If a given file is pointing to `valet.sock`, it's targeting the old global PHP version; * update it to point to the new custom sock file for that version. * If a given file is pointing the custom sock file for the new global version, that new * version will now be hosted at `valet.sock`, so update the config file to point to that instead. @@ -336,7 +338,7 @@ public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersio * * @return array */ - public function getPhpVersionsToPerformRestart() + public function utilizedPhpVersions() { $fpmSockFiles = $this->brew->supportedPhpVersions()->map(function ($version) { return $this->fpmSockName($this->normalizePhpVersion($version)); @@ -356,7 +358,7 @@ public function getPhpVersionsToPerformRestart() // for example, "valet74.sock" will output "php74" $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); - return $this->normalizePhpVersion($phpVersion); // example output php@7.4 + return $this->normalizePhpVersion($phpVersion); // Example output php@7.4 } } })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->toArray(); diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 1ee192c9a..14240b58d 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -193,7 +193,7 @@ public function proxies() /** * Determine if the provided site is a valid site, whether parked or linked. * - * @param string $valetSite + * @param string $valetSite * @return bool */ public function isValidSite($valetSite) @@ -489,7 +489,7 @@ public function secured() public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $caExpireInYears = 20) { // Extract in order to later preserve custom PHP version config when securing - $phpVersion = $this->extractPhpVersion($url); + $phpVersion = $this->customPhpVersion($url); $this->unsecure($url); @@ -506,7 +506,7 @@ public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $ $siteConf = $this->buildSecureNginxServer($url, $siteConf); - // If they user had isolated the PHP version for this site, swap out .sock file + // If the user had isolated the PHP version for this site, swap out .sock file if ($phpVersion) { $siteConf = $this->replaceSockFile($siteConf, "valet{$phpVersion}.sock", $phpVersion); } @@ -711,6 +711,25 @@ public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) $this->files->putAsUser($this->nginxPath($valetSite), $siteConf); } + /** + * Remove PHP Version isolation from a specific site + * + * @param string $valetSite + * @return void + */ + function removeIsolation($valetSite) + { + // When site has SSL certificate, just re-generate the nginx config. + // It will be using the `valet.sock` by default from now + if ($this->files->exists($this->certificatesPath($valetSite, 'crt'))) { + $siteConf = $this->buildSecureNginxServer($valetSite); + $this->files->putAsUser($this->nginxPath($valetSite), $siteConf); + } else { + // When site doesn't have SSL, removing the custom nginx config will remove isolation + $this->files->unlink($this->nginxPath($valetSite)); + } + } + /** * Unsecure the given URL so that it will use HTTP again. * @@ -719,7 +738,8 @@ public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) */ public function unsecure($url) { - $phpVersion = $this->extractPhpVersion($url); // let's try to preserve the isolated php version here. Example output: 74 + // Extract in order to later preserve custom PHP version config when unsecuring. Example output: "74" + $phpVersion = $this->customPhpVersion($url); if ($this->files->exists($this->certificatesPath($url, 'crt'))) { $this->files->unlink($this->nginxPath($url)); @@ -737,8 +757,7 @@ public function unsecure($url) $url, '@laravel.valet' )); - // if user had any isolated php version, let's swap the .sock file, - // so it still uses the old php version + // If the user had isolated the PHP version for this site, swap out .sock file if ($phpVersion) { $this->installSiteConfig($url, "valet{$phpVersion}.sock", $phpVersion); } @@ -1045,10 +1064,10 @@ public function replaceLoopback($siteConf) /** * Extract PHP version of exising nginx conifg. * - * @param $url + * @param string $url * @return string|void */ - public function extractPhpVersion($url) + public function customPhpVersion($url) { if ($this->files->exists($this->nginxPath($url))) { $siteConf = $this->files->get($this->nginxPath($url)); @@ -1064,9 +1083,9 @@ public function extractPhpVersion($url) /** * Replace .sock file in an Nginx site configuration file contents. * - * @param string $siteConf - * @param string $sockFile - * @param string $phpVersion + * @param string $siteConf + * @param string $sockFile + * @param string $phpVersion * @return string */ public function replaceSockFile($siteConf, $sockFile, $phpVersion) diff --git a/cli/valet.php b/cli/valet.php index 2cd2cbf14..617fdad26 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -509,23 +509,34 @@ } } - PhpFpm::validateRequestedVersion($phpVersion); - if ($site) { - if ($site == '.') { // allow user to use dot as current dir's site `--site=.` - $site = Site::host(getcwd()).'.'.Configuration::read()['tld']; + $tld = Configuration::read()['tld']; + + if ($site == '.') { // Allow user to use dot as current dir's site `--site=.` + $site = Site::host(getcwd()).'.'.$tld; + } + + if (false === strpos($site, '.'.$tld)) { + $site = $site.'.'.$tld; // Allow user to pass just the site's directory name } if (! Site::isValidSite($site)) { return warning(sprintf('Site %s could not be found in valet site list.', $site)); } - $newVersion = PhpFpm::useVersion($phpVersion, $force, $site); + if ($phpVersion == 'default') { + Site::removeIsolation($site); + Nginx::restart(); - Site::installSiteConfig($site, PhpFpm::fpmSockName($phpVersion), $phpVersion); - Nginx::restart(); + info(sprintf('The [%s] site is now using default php version.', $site)); + } else { + $newVersion = PhpFpm::useVersion($phpVersion, $force, $site); + + Site::installSiteConfig($site, PhpFpm::fpmSockName($phpVersion), $phpVersion); + Nginx::restart(); - info(sprintf('The [%s] site is now using %s.', $site, $newVersion)); + info(sprintf('The [%s] site is now using %s.', $site, $newVersion)); + } } else { $newVersion = PhpFpm::useVersion($phpVersion, $force); Nginx::restart(); From 8de8d9bb2604b676c93b2caa985211195deccdc0 Mon Sep 17 00:00:00 2001 From: NasirNobin Date: Tue, 15 Feb 2022 04:49:03 +0600 Subject: [PATCH 04/41] Stop unused PHP versions --- cli/Valet/PhpFpm.php | 19 +++++++++++++++++-- cli/Valet/Site.php | 8 ++++---- cli/valet.php | 5 +++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 44114b0c0..2fab2c8ef 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -178,6 +178,21 @@ public function stopRunning() ); } + /** + * Stop PHP, if a specific version isn't being used globally or by any sites. + * + * @param string $phpVersion + * @return void + */ + public function maybeStop($phpVersion) + { + $phpVersion = $this->normalizePhpVersion($phpVersion); + + if(! in_array($phpVersion, $this->utilizedPhpVersions())) { + $this->brew->stopService($phpVersion); + } + } + /** * Use a specific version of php. * @@ -305,8 +320,8 @@ public function fpmSockName($phpVersion = null) * If a given file is pointing the custom sock file for the new global version, that new * version will now be hosted at `valet.sock`, so update the config file to point to that instead. * - * @param $newPhpVersion - * @param $oldPhpVersion + * @param string $newPhpVersion + * @param string $oldPhpVersion * @return void */ public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersion) diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 14240b58d..f98b23415 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -712,12 +712,12 @@ public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) } /** - * Remove PHP Version isolation from a specific site + * Remove PHP Version isolation from a specific site. * * @param string $valetSite * @return void */ - function removeIsolation($valetSite) + public function removeIsolation($valetSite) { // When site has SSL certificate, just re-generate the nginx config. // It will be using the `valet.sock` by default from now @@ -1064,7 +1064,7 @@ public function replaceLoopback($siteConf) /** * Extract PHP version of exising nginx conifg. * - * @param string $url + * @param string $url * @return string|void */ public function customPhpVersion($url) @@ -1075,7 +1075,7 @@ public function customPhpVersion($url) if (starts_with($siteConf, '# Valet isolated PHP version')) { $firstLine = explode(PHP_EOL, $siteConf)[0]; - return preg_replace("/[^\d]*/", '', $firstLine); + return preg_replace("/[^\d]*/", '', $firstLine); // Example output: "74" or "81" } } } diff --git a/cli/valet.php b/cli/valet.php index 617fdad26..dd7cf2124 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -525,7 +525,12 @@ } if ($phpVersion == 'default') { + $customPhpVersion = Site::customPhpVersion($site); // Example output: "74" Site::removeIsolation($site); + if ($customPhpVersion) { + PhpFpm::maybeStop('php' .$customPhpVersion); + } + Nginx::restart(); info(sprintf('The [%s] site is now using default php version.', $site)); From 794e366ba5b1f79d67b45bf0b95a80f8887bdd7b Mon Sep 17 00:00:00 2001 From: NasirNobin Date: Tue, 15 Feb 2022 05:05:21 +0600 Subject: [PATCH 05/41] StyleCI Patch --- cli/Valet/PhpFpm.php | 2 +- cli/valet.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 2fab2c8ef..8cb34f90a 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -188,7 +188,7 @@ public function maybeStop($phpVersion) { $phpVersion = $this->normalizePhpVersion($phpVersion); - if(! in_array($phpVersion, $this->utilizedPhpVersions())) { + if (! in_array($phpVersion, $this->utilizedPhpVersions())) { $this->brew->stopService($phpVersion); } } diff --git a/cli/valet.php b/cli/valet.php index dd7cf2124..fe54f539c 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -528,7 +528,7 @@ $customPhpVersion = Site::customPhpVersion($site); // Example output: "74" Site::removeIsolation($site); if ($customPhpVersion) { - PhpFpm::maybeStop('php' .$customPhpVersion); + PhpFpm::maybeStop('php'.$customPhpVersion); } Nginx::restart(); From 5c1043776e7bc4917173285805e2b12fad10b237 Mon Sep 17 00:00:00 2001 From: Nasir Uddin Nobin Date: Tue, 15 Feb 2022 16:44:29 +0600 Subject: [PATCH 06/41] Apply refactor & cleanup from the code review --- cli/Valet/PhpFpm.php | 117 ++++++++++++++++++++++++++++++------------- cli/Valet/Site.php | 32 +++++++----- cli/valet.php | 40 +-------------- tests/PhpFpmTest.php | 20 ++++++++ 4 files changed, 123 insertions(+), 86 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 8cb34f90a..5f7cc8644 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -9,6 +9,9 @@ class PhpFpm public $brew; public $cli; public $files; + public $config; + public $site; + public $nginx; public $taps = [ 'homebrew/homebrew-core', @@ -21,22 +24,27 @@ class PhpFpm * @param Brew $brew * @param CommandLine $cli * @param Filesystem $files + * @param Configuration $config + * @param Site $site + * @param Nginx $nginx * @return void */ - public function __construct(Brew $brew, CommandLine $cli, Filesystem $files) + public function __construct(Brew $brew, CommandLine $cli, Filesystem $files, Configuration $config, Site $site, Nginx $nginx) { $this->cli = $cli; $this->brew = $brew; $this->files = $files; + $this->config = $config; + $this->site = $site; + $this->nginx = $nginx; } /** * Install and configure PhpFpm. * - * @param string|null $phpVersion * @return void */ - public function install($phpVersion = null) + public function install() { if (! $this->brew->hasInstalledPhp()) { $this->brew->ensureInstalled('php', [], $this->taps); @@ -44,9 +52,9 @@ public function install($phpVersion = null) $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); - $this->updateConfiguration($phpVersion); + $this->updateConfiguration(); - $this->restart($phpVersion); + $this->restart(); } /** @@ -181,11 +189,19 @@ public function stopRunning() /** * Stop PHP, if a specific version isn't being used globally or by any sites. * - * @param string $phpVersion + * @param string|null $phpVersion * @return void */ public function maybeStop($phpVersion) { + if (! $phpVersion) { + return; + } + + if (strpos($phpVersion, 'php') === false) { + $phpVersion = 'php'.$phpVersion; + } + $phpVersion = $this->normalizePhpVersion($phpVersion); if (! in_array($phpVersion, $this->utilizedPhpVersions())) { @@ -198,11 +214,29 @@ public function maybeStop($phpVersion) * * @param $version * @param bool $force - * @param string|null $site - * @return string + * @param string|null $directory + * @return string|void */ - public function useVersion($version, $force = false, $site = null) + public function useVersion($version, $force = false, $directory = null) { + if ($directory) { + $site = $this->site->getSiteUrl($directory); + + if (! $site) { + warning(sprintf('The [%s] site could not be found in valet site list.', $directory)); + exit(); + } + + if ($version == 'default') { // Remove isolation for this site + $customPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" + $this->site->removeIsolation($site); + $this->maybeStop($customPhpVersion); + $this->nginx->restart(); + info(sprintf('The [%s] site is now using default php version.', $site)); + exit(); + } + } + $version = $this->validateRequestedVersion($version); try { @@ -220,40 +254,55 @@ public function useVersion($version, $force = false, $site = null) } // Delete old Valet sock files, install the new version, and, if this is a global change, unlink and link PHP - if ($site) { + if ($directory && $site) { + $customPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($version)); - $this->install($version); - } else { - // Unlink the current global PHP if there is one installed - if ($this->brew->hasLinkedPhp()) { - $linkedPhp = $this->brew->linkedPhp(); + $this->updateConfiguration($version); + $this->site->installSiteConfig($site, $this->fpmSockName($version), $version); + + $this->maybeStop($customPhpVersion); + $this->restart($version); + $this->nginx->restart(); + info(sprintf('The [%s] site is now using %s.', $site, $version)); + exit(); + } - // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken - $this->updateConfiguration($linkedPhp); + // Unlink the current global PHP if there is one installed + if ($this->brew->hasLinkedPhp()) { + $linkedPhp = $this->brew->linkedPhp(); - // Update existing custom Nginx config files; if they're using the old or new PHP version, - // update them to the new correct sock file location - $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); + // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken + $this->updateConfiguration($linkedPhp); - $currentVersion = $this->brew->getLinkedPhpFormula(); - info(sprintf('Unlinking current version: %s', $currentVersion)); - $this->brew->unlink($currentVersion); - } + // Update existing custom Nginx config files; if they're using the old or new PHP version, + // update them to the new correct sock file location + $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); - info(sprintf('Linking new version: %s', $version)); - $this->brew->link($version, true); + $currentVersion = $this->brew->getLinkedPhpFormula(); + info(sprintf('Unlinking current version: %s', $currentVersion)); + $this->brew->unlink($currentVersion); + } - $this->stopRunning(); + info(sprintf('Linking new version: %s', $version)); + $this->brew->link($version, true); - // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts - $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); + $this->stopRunning(); - // ensure configuration is correct and start the linked version - $this->install(); - } + // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts + $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); + + // ensure configuration is correct and start the linked version + $this->install(); + + $newVersion = $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; + + $this->nginx->restart(); + + info(sprintf('Valet is now using %s.', $newVersion).PHP_EOL); + info('Note that you might need to run composer global update if your PHP version change affects the dependencies of global packages required by Composer.'); - return $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; + return $newVersion; } /** diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index f98b23415..06df7d3d3 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -191,17 +191,26 @@ public function proxies() } /** - * Determine if the provided site is a valid site, whether parked or linked. + * Determine if the provided site is a valid site, whether parked or linked and get the site url. * - * @param string $valetSite - * @return bool + * @param string $directory + * @return string|false */ - public function isValidSite($valetSite) + public function getSiteUrl($directory) { - // Remove .tld from sitename if it was provided - $siteName = str_replace('.'.$this->config->read()['tld'], '', $valetSite); + $tld = $this->config->read()['tld']; + + if ($directory == '.') { // Allow user to use dot as current dir's site `--site=.` + $directory = $this->host(getcwd()); + } + + $directory = str_replace('.'.$tld, '', $directory); // Remove .tld from sitename if it was provided - return $this->parked()->merge($this->links())->where('site', $siteName)->count() > 0; + if ($this->parked()->merge($this->links())->where('site', $directory)->count() > 0) { + return $directory.'.'.$tld; + } + + return false; // Invalid directory provided } /** @@ -692,7 +701,7 @@ public function buildSecureNginxServer($url, $siteConf = null) * * @param string $valetSite * @param string $fpmSockName - * @param $phpVersion + * @param string $phpVersion * @return void */ public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) @@ -1091,11 +1100,8 @@ public function customPhpVersion($url) public function replaceSockFile($siteConf, $sockFile, $phpVersion) { $siteConf = preg_replace('/valet[0-9]*.sock/', $sockFile, $siteConf); + $siteConf = preg_replace('/# Valet isolated PHP version.*\n/', '', $siteConf); // Remove `Valet isolated PHP version` line from config - if (! starts_with($siteConf, '# Valet isolated PHP version')) { - $siteConf = '# Valet isolated PHP version : '.$phpVersion.PHP_EOL.$siteConf; - } - - return $siteConf; + return '# Valet isolated PHP version : '.$phpVersion.PHP_EOL.$siteConf; } } diff --git a/cli/valet.php b/cli/valet.php index fe54f539c..f558f0be4 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -509,45 +509,7 @@ } } - if ($site) { - $tld = Configuration::read()['tld']; - - if ($site == '.') { // Allow user to use dot as current dir's site `--site=.` - $site = Site::host(getcwd()).'.'.$tld; - } - - if (false === strpos($site, '.'.$tld)) { - $site = $site.'.'.$tld; // Allow user to pass just the site's directory name - } - - if (! Site::isValidSite($site)) { - return warning(sprintf('Site %s could not be found in valet site list.', $site)); - } - - if ($phpVersion == 'default') { - $customPhpVersion = Site::customPhpVersion($site); // Example output: "74" - Site::removeIsolation($site); - if ($customPhpVersion) { - PhpFpm::maybeStop('php'.$customPhpVersion); - } - - Nginx::restart(); - - info(sprintf('The [%s] site is now using default php version.', $site)); - } else { - $newVersion = PhpFpm::useVersion($phpVersion, $force, $site); - - Site::installSiteConfig($site, PhpFpm::fpmSockName($phpVersion), $phpVersion); - Nginx::restart(); - - info(sprintf('The [%s] site is now using %s.', $site, $newVersion)); - } - } else { - $newVersion = PhpFpm::useVersion($phpVersion, $force); - Nginx::restart(); - info(sprintf('Valet is now using %s.', $newVersion).PHP_EOL); - info('Note that you might need to run composer global update if your PHP version change affects the dependencies of global packages required by Composer.'); - } + PhpFpm::useVersion($phpVersion, $force, $site); })->descriptions('Change the version of PHP used by valet', [ 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', '--site' => 'Isolate PHP version of a specific valet site. e.g: --site=site.test', diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 22124c9ae..5a000da5e 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -3,9 +3,12 @@ use Illuminate\Container\Container; use Valet\Brew; use Valet\CommandLine; +use Valet\Configuration; use Valet\Filesystem; +use Valet\Nginx; use Valet\PhpFpm; use function Valet\resolve; +use Valet\Site; use function Valet\swap; use function Valet\user; @@ -65,10 +68,16 @@ public function test_stopRunning_will_pass_filtered_result_of_getRunningServices public function test_use_version_will_convert_passed_php_version() { $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); + $siteMock = Mockery::mock(Site::class); + $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, resolve(CommandLine::class), resolve(Filesystem::class), + resolve(Configuration::class), + $siteMock, + $nginxMock, ])->makePartial(); $phpFpmMock->shouldReceive('install'); @@ -86,6 +95,8 @@ public function test_use_version_will_convert_passed_php_version() $brewMock->shouldReceive('getAllRunningServices')->andReturn(collect()); $brewMock->shouldReceive('stopService'); + $nginxMock->shouldReceive('restart'); + // Test both non prefixed and prefixed $this->assertSame('php@7.2', $phpFpmMock->useVersion('php7.2')); $this->assertSame('php@7.2', $phpFpmMock->useVersion('php72')); @@ -109,11 +120,18 @@ public function test_use_version_will_throw_if_version_not_supported() public function test_use_version_if_already_linked_php_will_unlink_before_installing() { $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); + $siteMock = Mockery::mock(Site::class); + $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, resolve(CommandLine::class), resolve(Filesystem::class), + resolve(Configuration::class), + $siteMock, + $nginxMock, ])->makePartial(); + $phpFpmMock->shouldReceive('install'); $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate'); @@ -132,6 +150,8 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $brewMock->shouldReceive('getAllRunningServices')->andReturn(collect()); $brewMock->shouldReceive('stopService'); + $nginxMock->shouldReceive('restart'); + // Test both non prefixed and prefixed $this->assertSame('php@7.2', $phpFpmMock->useVersion('php@7.2')); } From 49ca4ae46799d892cda82ae0d79c9e2d570edb0d Mon Sep 17 00:00:00 2001 From: Nasir Uddin Nobin Date: Wed, 16 Feb 2022 11:21:41 +0600 Subject: [PATCH 07/41] Apply suggestions from code review Co-authored-by: Matt Stauffer --- cli/Valet/PhpFpm.php | 15 +++++++-------- cli/Valet/Site.php | 18 +++++++++--------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 5f7cc8644..15f65d951 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -212,7 +212,7 @@ public function maybeStop($phpVersion) /** * Use a specific version of php. * - * @param $version + * @param string $version * @param bool $force * @param string|null $directory * @return string|void @@ -223,8 +223,8 @@ public function useVersion($version, $force = false, $directory = null) $site = $this->site->getSiteUrl($directory); if (! $site) { - warning(sprintf('The [%s] site could not be found in valet site list.', $directory)); - exit(); + warning(sprintf("The [%s] site could not be found in Valet's site list.", $directory)); + return; } if ($version == 'default') { // Remove isolation for this site @@ -232,8 +232,8 @@ public function useVersion($version, $force = false, $directory = null) $this->site->removeIsolation($site); $this->maybeStop($customPhpVersion); $this->nginx->restart(); - info(sprintf('The [%s] site is now using default php version.', $site)); - exit(); + info(sprintf('The site [%s] is now using the default PHP version.', $site)); + return; } } @@ -253,8 +253,7 @@ public function useVersion($version, $force = false, $directory = null) $this->brew->ensureInstalled($version, [], $this->taps); } - // Delete old Valet sock files, install the new version, and, if this is a global change, unlink and link PHP - if ($directory && $site) { + if ($directory) { $customPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($version)); $this->updateConfiguration($version); @@ -264,7 +263,7 @@ public function useVersion($version, $force = false, $directory = null) $this->restart($version); $this->nginx->restart(); info(sprintf('The [%s] site is now using %s.', $site, $version)); - exit(); + return; } // Unlink the current global PHP if there is one installed diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 06df7d3d3..be69085be 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -191,7 +191,7 @@ public function proxies() } /** - * Determine if the provided site is a valid site, whether parked or linked and get the site url. + * Get the site URL from a directory if it's a valid Valet site. * * @param string $directory * @return string|false @@ -200,17 +200,17 @@ public function getSiteUrl($directory) { $tld = $this->config->read()['tld']; - if ($directory == '.') { // Allow user to use dot as current dir's site `--site=.` + if ($directory == '.' || $directory == './') { // Allow user to use dot as current dir's site `--site=.` $directory = $this->host(getcwd()); } $directory = str_replace('.'.$tld, '', $directory); // Remove .tld from sitename if it was provided - if ($this->parked()->merge($this->links())->where('site', $directory)->count() > 0) { - return $directory.'.'.$tld; + if (! $this->parked()->merge($this->links())->where('site', $directory)->count() > 0) { + return false; // Invalid directory provided } - return false; // Invalid directory provided + return $directory.'.'.$tld; } /** @@ -697,7 +697,7 @@ public function buildSecureNginxServer($url, $siteConf = null) } /** - * Build the Nginx server for the given valet site. + * Build the Nginx server configuration for the given Valet site. * * @param string $valetSite * @param string $fpmSockName @@ -728,13 +728,13 @@ public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) */ public function removeIsolation($valetSite) { - // When site has SSL certificate, just re-generate the nginx config. - // It will be using the `valet.sock` by default from now + // If a site has an SSL certificate, we need to keep its custom config file, but we can + // just re-generate it without defining a custom `valet.sock` file if ($this->files->exists($this->certificatesPath($valetSite, 'crt'))) { $siteConf = $this->buildSecureNginxServer($valetSite); $this->files->putAsUser($this->nginxPath($valetSite), $siteConf); } else { - // When site doesn't have SSL, removing the custom nginx config will remove isolation + // When site doesn't have SSL, we can remove the custom nginx config file to remove isolation $this->files->unlink($this->nginxPath($valetSite)); } } From 3c8336791ff0d3b753ec85c5840662cb00b02361 Mon Sep 17 00:00:00 2001 From: NasirNobin Date: Wed, 16 Feb 2022 11:29:51 +0600 Subject: [PATCH 08/41] Apply more suggestions from code review --- cli/Valet/PhpFpm.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 15f65d951..a0e68334e 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -192,7 +192,7 @@ public function stopRunning() * @param string|null $phpVersion * @return void */ - public function maybeStop($phpVersion) + public function stopIfUnused($phpVersion) { if (! $phpVersion) { return; @@ -228,9 +228,9 @@ public function useVersion($version, $force = false, $directory = null) } if ($version == 'default') { // Remove isolation for this site - $customPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" + $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" $this->site->removeIsolation($site); - $this->maybeStop($customPhpVersion); + $this->stopIfUnused($oldCustomPhpVersion); $this->nginx->restart(); info(sprintf('The site [%s] is now using the default PHP version.', $site)); return; @@ -254,15 +254,15 @@ public function useVersion($version, $force = false, $directory = null) } if ($directory) { - $customPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" + $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($version)); $this->updateConfiguration($version); $this->site->installSiteConfig($site, $this->fpmSockName($version), $version); - $this->maybeStop($customPhpVersion); + $this->stopIfUnused($oldCustomPhpVersion); $this->restart($version); $this->nginx->restart(); - info(sprintf('The [%s] site is now using %s.', $site, $version)); + info(sprintf('The site [%s] is now using %s.', $site, $version)); return; } From cc41e3c19faca5b5847fe3cea1762d4d9cb147b0 Mon Sep 17 00:00:00 2001 From: Nasir Uddin Nobin Date: Fri, 18 Feb 2022 05:59:22 +0600 Subject: [PATCH 09/41] Update cli/Valet/PhpFpm.php Co-authored-by: Matt Stauffer --- cli/Valet/PhpFpm.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index a0e68334e..32711960c 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -396,8 +396,8 @@ public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersio } /** - * Get a list of all PHP versions currently serving "isolated sites" (sites with custom Nginx - * configs pointing them to a specific PHP version). + * Get a list including the global PHP version and allPHP versions currently serving "isolated sites" (sites with + * custom Nginx configs pointing them to a specific PHP version). * * @return array */ From 9a5d30bb69343b7defaee19d67431c30f29fb14b Mon Sep 17 00:00:00 2001 From: Nasir Uddin Nobin Date: Fri, 18 Feb 2022 15:14:57 +0600 Subject: [PATCH 10/41] Tests for Parallel PHP Version Support --- cli/Valet/PhpFpm.php | 12 +- tests/PhpFpmTest.php | 285 ++++++++++++++++++++++++++++++++++++++++++- tests/SiteTest.php | 255 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 545 insertions(+), 7 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 32711960c..3d7bc74ae 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -223,8 +223,12 @@ public function useVersion($version, $force = false, $directory = null) $site = $this->site->getSiteUrl($directory); if (! $site) { - warning(sprintf("The [%s] site could not be found in Valet's site list.", $directory)); - return; + throw new DomainException( + sprintf( + "The [%s] site could not be found in Valet's site list.", + $directory + ) + ); } if ($version == 'default') { // Remove isolation for this site @@ -233,6 +237,7 @@ public function useVersion($version, $force = false, $directory = null) $this->stopIfUnused($oldCustomPhpVersion); $this->nginx->restart(); info(sprintf('The site [%s] is now using the default PHP version.', $site)); + return; } } @@ -263,6 +268,7 @@ public function useVersion($version, $force = false, $directory = null) $this->restart($version); $this->nginx->restart(); info(sprintf('The site [%s] is now using %s.', $site, $version)); + return; } @@ -424,6 +430,6 @@ public function utilizedPhpVersions() return $this->normalizePhpVersion($phpVersion); // Example output php@7.4 } } - })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->toArray(); + })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->values()->toArray(); } } diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 5a000da5e..511181b95 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -40,6 +40,186 @@ public function test_fpm_is_configured_with_the_correct_user_group_and_port() $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); $this->assertStringContainsString("\ngroup = staff", $contents); $this->assertStringContainsString("\nlisten = ".VALET_HOME_PATH.'/valet.sock', $contents); + + // Passing speicifc version will change the .sock file + resolve(StubForUpdatingFpmConfigFiles::class)->updateConfiguration('php@7.2'); + $contents = file_get_contents(__DIR__.'/output/fpm.conf'); + $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); + $this->assertStringContainsString("\ngroup = staff", $contents); + $this->assertStringContainsString("\nlisten = ".VALET_HOME_PATH.'/valet72.sock', $contents); + } + + public function test_it_can_generate_sock_file_name_from_php_version() + { + $this->assertEquals('valet72.sock', resolve(PhpFpm::class)->fpmSockName('php@7.2')); + $this->assertEquals('valet72.sock', resolve(PhpFpm::class)->fpmSockName('php@72')); + $this->assertEquals('valet72.sock', resolve(PhpFpm::class)->fpmSockName('php72')); + $this->assertEquals('valet72.sock', resolve(PhpFpm::class)->fpmSockName('72')); + } + + public function test_utilized_php_versions() + { + $fileSystemMock = Mockery::mock(Filesystem::class); + $brewMock = Mockery::mock(Brew::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + $brewMock, + Mockery::mock(CommandLine::class), + $fileSystemMock, + resolve(Configuration::class), + Mockery::mock(Site::class), + Mockery::mock(Nginx::class), + ])->makePartial(); + + swap(PhpFpm::class, $phpFpmMock); + + $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ + 'php@7.1', + 'php@7.2', + 'php@7.3', + 'php@7.4', + ])); + + $brewMock->shouldReceive('getLinkedPhpFormula')->andReturn('php@7.3'); + + $fileSystemMock->shouldReceive('scandir') + ->once() + ->with(VALET_HOME_PATH.'/Nginx') + ->andReturn(['.gitkeep', 'isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test']); + + $fileSystemMock->shouldNotReceive('get')->with(VALET_HOME_PATH.'/Nginx/.gitkeep'); + + $sites = [ + [ + 'site' => 'isolated-site-71.test', + 'conf' => '# Valet isolated PHP version : 71'.PHP_EOL.'valet71.sock', + ], + [ + 'site' => 'isolated-site-72.test', + 'conf' => '# Valet isolated PHP version : php@7.2'.PHP_EOL.'valet72.sock', + ], + [ + 'site' => 'isolated-site-73.test', + 'conf' => '# Valet isolated PHP version : 73'.PHP_EOL.'valet.sock', + ], + ]; + + foreach ($sites as $site) { + $fileSystemMock->shouldReceive('get')->once()->with(VALET_HOME_PATH.'/Nginx/'.$site['site'])->andReturn($site['conf']); + } + + $this->assertEquals(['php@7.1', 'php@7.2', 'php@7.3'], resolve(PhpFpm::class)->utilizedPhpVersions()); + } + + public function test_global_php_version_update_will_swap_socks() + { + $fileSystemMock = Mockery::mock(Filesystem::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + Mockery::mock(Brew::class), + Mockery::mock(CommandLine::class), + $fileSystemMock, + resolve(Configuration::class), + Mockery::mock(Site::class), + Mockery::mock(Nginx::class), + ])->makePartial(); + + swap(PhpFpm::class, $phpFpmMock); + + $fileSystemMock->shouldReceive('scandir') + ->once() + ->with(VALET_HOME_PATH.'/Nginx') + ->andReturn([ + '.gitkeep', + 'isolated-site-71.test', + 'isolated-site-72.test', + 'isolated-site-73.test', + 'non-isolated-site.test', + ]); + + // Skip dotfiles + $fileSystemMock->shouldNotReceive('get')->with(VALET_HOME_PATH.'/Nginx/.gitkeep'); + + // Any isolated site running on php72 would be replaced with default valet.sock, + // as 72 will be the default version after the global PHP version switch + $fileSystemMock->shouldReceive('get') + ->once() + ->with(VALET_HOME_PATH.'/Nginx/isolated-site-72.test') + ->andReturn('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }'); + + $fileSystemMock->shouldReceive('put')->once()->withArgs([ + VALET_HOME_PATH.'/Nginx/isolated-site-72.test', + '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', + ]); + + // Any isolated site running on current PHP version (with valet.sock), + // should be still be running on the same version after the global version update + $fileSystemMock->shouldReceive('get') + ->once() + ->with(VALET_HOME_PATH.'/Nginx/isolated-site-71.test') + ->andReturn('# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet.sock }'); + + $fileSystemMock->shouldReceive('put')->once()->withArgs([ + VALET_HOME_PATH.'/Nginx/isolated-site-71.test', + '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', + ]); + + // PHP 7.3 sites won't be affected here + $fileSystemMock->shouldReceive('get') + ->once() + ->with(VALET_HOME_PATH.'/Nginx/isolated-site-73.test') + ->andReturn('# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }'); + + $fileSystemMock->shouldNotReceive('put')->withArgs([ + VALET_HOME_PATH.'/Nginx/isolated-site-73.test', + Mockery::any(), + ]); + + // Nginx config that doesn't have the isolation header, It would not swap .sock files + $fileSystemMock->shouldReceive('get')->once()->with(VALET_HOME_PATH.'/Nginx/non-isolated-site.test')->andReturn('valet.sock'); + $fileSystemMock->shouldNotReceive('put')->withArgs([ + VALET_HOME_PATH.'/Nginx/non-isolated-site.test', + 'valet71.sock', + ]); + + // Switching from php7.1 to php7.2 + resolve(PhpFpm::class)->updateConfigurationForGlobalUpdate('php@7.2', 'php@7.1'); + } + + public function test_stop_unused_php_versions() + { + $brewMock = Mockery::mock(Brew::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + $brewMock, + Mockery::mock(CommandLine::class), + Mockery::mock(Filesystem::class), + resolve(Configuration::class), + Mockery::mock(Site::class), + Mockery::mock(Nginx::class), + ])->makePartial(); + + swap(PhpFpm::class, $phpFpmMock); + + $phpFpmMock->shouldReceive('utilizedPhpVersions')->andReturn([ + 'php@7.1', + 'php@7.2', + ]); + + // Would do nothing + resolve(PhpFpm::class)->stopIfUnused(null); + + // Currently, not utilizeing this PHP version, should be stopped + $brewMock->shouldReceive('stopService')->times(3)->with('php@7.3'); + resolve(PhpFpm::class)->stopIfUnused('73'); + resolve(PhpFpm::class)->stopIfUnused('php73'); + resolve(PhpFpm::class)->stopIfUnused('php@7.3'); + + // Utilizeing PHP Versions, should not receive stop command + $brewMock->shouldNotReceive('stopService')->with('php@7.1'); + $brewMock->shouldNotReceive('stopService')->with('php@7.2'); + resolve(PhpFpm::class)->stopIfUnused('php@7.1'); + resolve(PhpFpm::class)->stopIfUnused('php@7.2'); } public function test_stopRunning_will_pass_filtered_result_of_getRunningServices_to_stopService() @@ -122,24 +302,32 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); + $cliMock = Mockery::mock(CommandLine::class); + $fileSystemMock = Mockery::mock(Filesystem::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, - resolve(CommandLine::class), - resolve(Filesystem::class), + $cliMock, + $fileSystemMock, resolve(Configuration::class), $siteMock, $nginxMock, ])->makePartial(); $phpFpmMock->shouldReceive('install'); - $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate'); + $cliMock->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet*.sock')->once(); + $fileSystemMock->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock')->once(); + + $phpFpmMock->shouldReceive('updateConfiguration')->with('php@7.1')->once(); + $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate')->withArgs(['php@7.2', 'php@7.1'])->once(); $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', 'php@5.6', ])); + $brewMock->shouldReceive('hasLinkedPhp')->andReturn(true); + $brewMock->shouldReceive('linkedPhp')->andReturn('php@7.1'); $brewMock->shouldReceive('getLinkedPhpFormula')->andReturn('php@7.1'); $brewMock->shouldReceive('unlink')->with('php@7.1'); $brewMock->shouldReceive('ensureInstalled')->with('php@7.2', [], $phpFpmMock->taps); @@ -152,9 +340,98 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $nginxMock->shouldReceive('restart'); - // Test both non prefixed and prefixed $this->assertSame('php@7.2', $phpFpmMock->useVersion('php@7.2')); } + + public function test_use_version_with_site_paramter_will_isolate_a_site() + { + $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); + $siteMock = Mockery::mock(Site::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + $brewMock, + resolve(CommandLine::class), + resolve(Filesystem::class), + resolve(Configuration::class), + $siteMock, + $nginxMock, + ])->makePartial(); + + $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ + 'php@7.2', + 'php@5.6', + ])); + + $brewMock->shouldReceive('ensureInstalled')->with('php@7.2', [], $phpFpmMock->taps); + $brewMock->shouldReceive('installed')->with('php@7.2'); + $brewMock->shouldReceive('determineAliasedVersion')->with('php@7.2')->andReturn('php@7.2'); + $brewMock->shouldReceive('linkedPhp')->once(); + + $siteMock->shouldReceive('getSiteUrl')->with('test')->andReturn('test.test'); + $siteMock->shouldReceive('installSiteConfig')->withArgs(['test.test', 'valet72.sock', 'php@7.2']); + $siteMock->shouldReceive('customPhpVersion')->with('test.test')->andReturn('72'); + + $phpFpmMock->shouldReceive('stopIfUnused')->with('72')->once(); + $phpFpmMock->shouldReceive('updateConfiguration')->with('php@7.2')->once(); + $phpFpmMock->shouldReceive('restart')->with('php@7.2')->once(); + + $nginxMock->shouldReceive('restart'); + + // These should only run when doing global PHP switches + $brewMock->shouldNotReceive('stopService'); + $brewMock->shouldNotReceive('link'); + $brewMock->shouldNotReceive('unlink'); + $phpFpmMock->shouldNotReceive('stopRunning'); + $phpFpmMock->shouldNotReceive('install'); + $phpFpmMock->shouldNotReceive('updateConfigurationForGlobalUpdate'); + + $this->assertSame(null, $phpFpmMock->useVersion('php@7.2', false, 'test')); + } + + public function test_use_version_can_remove_isolation_for_a_site() + { + $nginxMock = Mockery::mock(Nginx::class); + $siteMock = Mockery::mock(Site::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + Mockery::mock(Brew::class), + resolve(CommandLine::class), + resolve(Filesystem::class), + resolve(Configuration::class), + $siteMock, + $nginxMock, + ])->makePartial(); + + $siteMock->shouldReceive('getSiteUrl')->with('test')->andReturn('test.test'); + $siteMock->shouldReceive('customPhpVersion')->with('test.test')->andReturn('74'); + $siteMock->shouldReceive('removeIsolation')->with('test.test')->once(); + $phpFpmMock->shouldReceive('stopIfUnused')->with('74'); + $nginxMock->shouldReceive('restart'); + + $this->assertSame(null, $phpFpmMock->useVersion('default', false, 'test')); + } + + public function test_use_version_will_throw_if_site_is_not_parked_or_linked() + { + $siteMock = Mockery::mock(Site::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + Mockery::mock(Brew::class), + resolve(CommandLine::class), + resolve(Filesystem::class), + resolve(Configuration::class), + $siteMock, + Mockery::mock(Nginx::class), + ])->makePartial(); + + $this->expectException(DomainException::class); + $this->expectExceptionMessage("The [test] site could not be found in Valet's site list."); + + $siteMock->shouldReceive('getSiteUrl'); + + $this->assertSame(null, $phpFpmMock->useVersion('default', false, 'test')); + } } class StubForUpdatingFpmConfigFiles extends PhpFpm diff --git a/tests/SiteTest.php b/tests/SiteTest.php index 388b53242..dd7a8ff43 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -526,6 +526,261 @@ public function test_remove_proxy() $this->assertEquals([], $site->proxies()->all()); } + + public function test_get_site_url_from_directory() + { + $config = Mockery::mock(Configuration::class); + + swap(Configuration::class, $config); + + $siteMock = Mockery::mock(Site::class, [ + resolve(Configuration::class), + resolve(CommandLine::class), + resolve(Filesystem::class), + ])->makePartial(); + + swap(Site::class, $siteMock); + + $config->shouldReceive('read') + ->andReturn(['tld' => 'test', 'loopback' => VALET_LOOPBACK, 'paths' => []]); + + $siteMock->shouldReceive('parked') + ->andReturn(collect([ + 'site1' => [ + 'site' => 'site1', + 'secured' => '', + 'url' => 'http://site1.test', + 'path' => '/Users/name/code/site1', + ], + ])); + + $siteMock->shouldReceive('links')->andReturn(collect([ + 'site2' => [ + 'site' => 'site2', + 'secured' => 'X', + 'url' => 'http://site2.test', + 'path' => '/Users/name/code/site2', + ], + ])); + + $siteMock->shouldReceive('host')->andReturn('site1'); + + $site = resolve(Site::class); + + $this->assertEquals('site1.test', $site->getSiteUrl('.')); + $this->assertEquals('site1.test', $site->getSiteUrl('./')); + + $this->assertEquals('site1.test', $site->getSiteUrl('site1')); + $this->assertEquals('site1.test', $site->getSiteUrl('site1.test')); + + $this->assertEquals('site2.test', $site->getSiteUrl('site2')); + $this->assertEquals('site2.test', $site->getSiteUrl('site2.test')); + + $this->assertEquals(false, $site->getSiteUrl('site3')); + $this->assertEquals(false, $site->getSiteUrl('site3.test')); + } + + public function test_adding_ssl_certificate_would_preserve_isolation() + { + $files = Mockery::mock(Filesystem::class); + $config = Mockery::mock(Configuration::class); + + $siteMock = Mockery::mock(Site::class, [ + $config, + Mockery::mock(CommandLine::class), + $files, + ])->makePartial(); + + swap(Site::class, $siteMock); + + $siteMock->shouldReceive('unsecure'); + $files->shouldReceive('ensureDirExists'); + $files->shouldReceive('putAsUser'); + $siteMock->shouldReceive('createCa'); + $siteMock->shouldReceive('createCertificate'); + $siteMock->shouldReceive('buildSecureNginxServer'); + + // If site has an isolated PHP version for the site, it would replace .sock file + $siteMock->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once(); + $siteMock->shouldReceive('replaceSockFile')->withArgs([Mockery::any(), 'valet73.sock', '73'])->once(); + resolve(Site::class)->secure('site1.test'); + + // Sites without isolated PHP version, should not replace anything + $siteMock->shouldReceive('customPhpVersion')->with('site2.test')->andReturn(null)->once(); + $siteMock->shouldNotReceive('replaceSockFile'); + resolve(Site::class)->secure('site2.test'); + } + + public function test_removing_ssl_certificate_would_preserve_isolation() + { + $files = Mockery::mock(Filesystem::class); + $config = Mockery::mock(Configuration::class); + $cli = Mockery::mock(CommandLine::class); + + $siteMock = Mockery::mock(Site::class, [ + $config, + $cli, + $files, + ])->makePartial(); + + swap(Site::class, $siteMock); + + $cli->shouldReceive('run'); + $files->shouldReceive('exists')->andReturn(false); + + // If site has an isolated PHP version, it would install nginx site config + $siteMock->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once(); + $siteMock->shouldReceive('installSiteConfig')->withArgs(['site1.test', 'valet73.sock', '73'])->once(); + resolve(Site::class)->unsecure('site1.test'); + + // Site without a custom PHP version, should not install site config + $siteMock->shouldReceive('customPhpVersion')->with('site2.test')->andReturn(null)->once(); + $siteMock->shouldNotReceive('installSiteConfig'); + resolve(Site::class)->unsecure('site2.test'); + } + + public function test_can_install_nginx_site_config_for_specific_php_version() + { + $files = Mockery::mock(Filesystem::class); + $config = Mockery::mock(Configuration::class); + + $siteMock = Mockery::mock(Site::class, [ + $config, + resolve(CommandLine::class), + $files, + ])->makePartial(); + + $config->shouldReceive('read') + ->andReturn(['tld' => 'test', 'loopback' => VALET_LOOPBACK]); + + // If Nginx config exists for the site, modify exising config + $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site1.test'))->andReturn(true); + + $files->shouldReceive('get') + ->once() + ->with($siteMock->nginxPath('site1.test')) + ->andReturn('# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }'); + + $files->shouldReceive('putAsUser') + ->once() + ->withArgs([ + $siteMock->nginxPath('site1.test'), + '# Valet isolated PHP version : php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', + ]); + + $siteMock->installSiteConfig('site1.test', 'valet80.sock', 'php@8.0'); + + // When there's no Nginx file exists, create new config from the template + $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site2.test'))->andReturn(false); + $files->shouldReceive('get') + ->once() + ->with(dirname(__DIR__).'/cli/Valet/../stubs/site.valet.conf') + ->andReturn(file_get_contents(__DIR__.'/../cli/stubs/site.valet.conf')); + + $files->shouldReceive('putAsUser') + ->once() + ->withArgs([ + $siteMock->nginxPath('site2.test'), + Mockery::on(function ($argument) { + return preg_match('/^# Valet isolated PHP version : php@8.0/', $argument) + && preg_match('#fastcgi_pass "unix:.*/valet80.sock#', $argument) + && strpos($argument, 'server_name site2.test www.site2.test *.site2.test;') !== false; + }), + ]); + + $siteMock->installSiteConfig('site2.test', 'valet80.sock', 'php@8.0'); + } + + public function test_removeing_isolation() + { + $files = Mockery::mock(Filesystem::class); + + $siteMock = Mockery::mock(Site::class, [ + resolve(Configuration::class), + resolve(CommandLine::class), + $files, + ])->makePartial(); + + swap(Site::class, $siteMock); + + // SSL Site + $files->shouldReceive('exists')->once()->with($siteMock->certificatesPath('site1.test', 'crt'))->andReturn(true); + $files->shouldReceive('putAsUser')->withArgs([$siteMock->nginxPath('site1.test'), Mockery::any()])->once(); + $siteMock->shouldReceive('buildSecureNginxServer')->once()->with('site1.test'); + resolve(Site::class)->removeIsolation('site1.test'); + + // Non-SSL Site + $files->shouldReceive('exists')->once()->with($siteMock->certificatesPath('site2.test', 'crt'))->andReturn(false); + $files->shouldReceive('unlink')->with($siteMock->nginxPath('site2.test'))->once(); + $siteMock->shouldNotReceive('buildSecureNginxServer')->with('site2.test'); + resolve(Site::class)->removeIsolation('site2.test'); + } + + public function test_retrive_custom_php_version_from_nginx_config() + { + $files = Mockery::mock(Filesystem::class); + + $siteMock = Mockery::mock(Site::class, [ + resolve(Configuration::class), + resolve(CommandLine::class), + $files, + ])->makePartial(); + + swap(Site::class, $siteMock); + + // Site with isolated PHP version + $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site1.test'))->andReturn(true); + $files->shouldReceive('get') + ->once() + ->with($siteMock->nginxPath('site1.test')) + ->andReturn('# Valet isolated PHP version : php@7.4'); + $this->assertEquals('74', resolve(Site::class)->customPhpVersion('site1.test')); + + // Site without any custom nginx config + $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site2.test'))->andReturn(false); + $files->shouldNotReceive('get')->with($siteMock->nginxPath('site2.test')); + $this->assertEquals(null, resolve(Site::class)->customPhpVersion('site2.test')); + + // Site with a custom nginx config, but doesn't have the header + $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site3.test'))->andReturn(true); + $files->shouldReceive('get') + ->once() + ->with($siteMock->nginxPath('site3.test')) + ->andReturn('server { }'); + $this->assertEquals(null, resolve(Site::class)->customPhpVersion('site3.test')); + } + + public function test_replace_sock_file_in_nginx_config() + { + $site = resolve(Site::class); + + // Switiching to php71, valet71.sock should be replaced with valet.sock + // It would prepend isolation header + $this->assertEquals( + '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet.sock }', + $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', 'valet.sock', '71') + ); + + // Switiching to php72, valet.sock should be replaced with valet72.sock + $this->assertEquals( + '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', + $site->replaceSockFile('server { fastcgi_pass: valet.sock }', 'valet72.sock', '72') + ); + + // Switiching to php73 from php72, valet72.sock should be replaced with valet73.sock + // Isolation header should be updated to 73 + $this->assertEquals( + '# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', + $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', 'valet73.sock', '73') + ); + + // Switiching to php72 from php74, valet72.sock should be replaced with valet74.sock + // Isolation header should be updated to php@7.4 + $this->assertEquals( + '# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', + $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'valet74.sock', 'php@7.4') + ); + } } class CommandLineFake extends CommandLine From 7a80a2e0eabfb8274a939a023e417a55e56451a7 Mon Sep 17 00:00:00 2001 From: Nasir Uddin Nobin Date: Sat, 19 Feb 2022 08:16:16 +0600 Subject: [PATCH 11/41] Apply suggestions from code review Co-authored-by: Matt Stauffer --- tests/PhpFpmTest.php | 8 ++++---- tests/SiteTest.php | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 511181b95..79dafdf36 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -41,7 +41,7 @@ public function test_fpm_is_configured_with_the_correct_user_group_and_port() $this->assertStringContainsString("\ngroup = staff", $contents); $this->assertStringContainsString("\nlisten = ".VALET_HOME_PATH.'/valet.sock', $contents); - // Passing speicifc version will change the .sock file + // Passing specific version will change the .sock file resolve(StubForUpdatingFpmConfigFiles::class)->updateConfiguration('php@7.2'); $contents = file_get_contents(__DIR__.'/output/fpm.conf'); $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); @@ -209,13 +209,13 @@ public function test_stop_unused_php_versions() // Would do nothing resolve(PhpFpm::class)->stopIfUnused(null); - // Currently, not utilizeing this PHP version, should be stopped + // This currently-un-used PHP version should be stopped $brewMock->shouldReceive('stopService')->times(3)->with('php@7.3'); resolve(PhpFpm::class)->stopIfUnused('73'); resolve(PhpFpm::class)->stopIfUnused('php73'); resolve(PhpFpm::class)->stopIfUnused('php@7.3'); - // Utilizeing PHP Versions, should not receive stop command + // These currently-used PHP versions should not be stopped $brewMock->shouldNotReceive('stopService')->with('php@7.1'); $brewMock->shouldNotReceive('stopService')->with('php@7.2'); resolve(PhpFpm::class)->stopIfUnused('php@7.1'); @@ -343,7 +343,7 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $this->assertSame('php@7.2', $phpFpmMock->useVersion('php@7.2')); } - public function test_use_version_with_site_paramter_will_isolate_a_site() + public function test_use_version_with_site_parameter_will_isolate_a_site() { $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); diff --git a/tests/SiteTest.php b/tests/SiteTest.php index dd7a8ff43..7ef268b63 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -527,7 +527,7 @@ public function test_remove_proxy() $this->assertEquals([], $site->proxies()->all()); } - public function test_get_site_url_from_directory() + public function test_gets_site_url_from_directory() { $config = Mockery::mock(Configuration::class); @@ -580,7 +580,7 @@ public function test_get_site_url_from_directory() $this->assertEquals(false, $site->getSiteUrl('site3.test')); } - public function test_adding_ssl_certificate_would_preserve_isolation() + public function test_isolation_will_persist_when_adding_ssl_certificate() { $files = Mockery::mock(Filesystem::class); $config = Mockery::mock(Configuration::class); @@ -605,13 +605,13 @@ public function test_adding_ssl_certificate_would_preserve_isolation() $siteMock->shouldReceive('replaceSockFile')->withArgs([Mockery::any(), 'valet73.sock', '73'])->once(); resolve(Site::class)->secure('site1.test'); - // Sites without isolated PHP version, should not replace anything + // For sites without an isolated PHP version, nothing should be replaced $siteMock->shouldReceive('customPhpVersion')->with('site2.test')->andReturn(null)->once(); $siteMock->shouldNotReceive('replaceSockFile'); resolve(Site::class)->secure('site2.test'); } - public function test_removing_ssl_certificate_would_preserve_isolation() + public function test_isolation_will_persist_when_removing_ssl_certificate() { $files = Mockery::mock(Filesystem::class); $config = Mockery::mock(Configuration::class); @@ -628,12 +628,12 @@ public function test_removing_ssl_certificate_would_preserve_isolation() $cli->shouldReceive('run'); $files->shouldReceive('exists')->andReturn(false); - // If site has an isolated PHP version, it would install nginx site config + // If a site has an isolated PHP version, there should still be a custom nginx site config $siteMock->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once(); $siteMock->shouldReceive('installSiteConfig')->withArgs(['site1.test', 'valet73.sock', '73'])->once(); resolve(Site::class)->unsecure('site1.test'); - // Site without a custom PHP version, should not install site config + // If a site doesn't have an isolated PHP version, there should no longer be a custom nginx site config $siteMock->shouldReceive('customPhpVersion')->with('site2.test')->andReturn(null)->once(); $siteMock->shouldNotReceive('installSiteConfig'); resolve(Site::class)->unsecure('site2.test'); @@ -670,7 +670,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() $siteMock->installSiteConfig('site1.test', 'valet80.sock', 'php@8.0'); - // When there's no Nginx file exists, create new config from the template + // When no Nginx file exists, it will create a new config file from the template $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site2.test'))->andReturn(false); $files->shouldReceive('get') ->once() @@ -691,7 +691,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() $siteMock->installSiteConfig('site2.test', 'valet80.sock', 'php@8.0'); } - public function test_removeing_isolation() + public function test_it_removes_isolation() { $files = Mockery::mock(Filesystem::class); @@ -716,7 +716,7 @@ public function test_removeing_isolation() resolve(Site::class)->removeIsolation('site2.test'); } - public function test_retrive_custom_php_version_from_nginx_config() + public function test_retrieves_custom_php_version_from_nginx_config() { $files = Mockery::mock(Filesystem::class); @@ -754,28 +754,28 @@ public function test_replace_sock_file_in_nginx_config() { $site = resolve(Site::class); - // Switiching to php71, valet71.sock should be replaced with valet.sock - // It would prepend isolation header + // When switching to php71, valet71.sock should be replaced with valet.sock; + // isolation header should be prepended $this->assertEquals( '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet.sock }', $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', 'valet.sock', '71') ); - // Switiching to php72, valet.sock should be replaced with valet72.sock + // When switching to php72, valet.sock should be replaced with valet72.sock $this->assertEquals( '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', $site->replaceSockFile('server { fastcgi_pass: valet.sock }', 'valet72.sock', '72') ); - // Switiching to php73 from php72, valet72.sock should be replaced with valet73.sock - // Isolation header should be updated to 73 + // When switching to php73 from php72, valet72.sock should be replaced with valet73.sock; + // isolation header should be updated to php@7.3 $this->assertEquals( '# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', 'valet73.sock', '73') ); - // Switiching to php72 from php74, valet72.sock should be replaced with valet74.sock - // Isolation header should be updated to php@7.4 + // When switching to php72 from php74, valet72.sock should be replaced with valet74.sock; + // isolation header should be updated to php@7.4 $this->assertEquals( '# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'valet74.sock', 'php@7.4') From eefc06b07f8ee57186ce898cacaaf33f9504d679 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sat, 12 Mar 2022 00:05:51 -0500 Subject: [PATCH 12/41] Drop PHP 5.6; extract site-specific PHP version isolation to its own commands --- .github/workflows/tests.yml | 2 +- cli/Valet/Brew.php | 2 - cli/Valet/PhpFpm.php | 184 +++++++++++++---------------- cli/Valet/Site.php | 5 +- cli/includes/compatibility.php | 4 +- cli/valet.php | 25 +++- composer.json | 2 +- tests/BrewTest.php | 23 +--- tests/PhpFpmTest.php | 34 +++--- tests/SiteTest.php | 8 +- tests/conf.d/error_log.ini | 5 + tests/conf.d/php-memory-limits.ini | 10 ++ 12 files changed, 154 insertions(+), 150 deletions(-) create mode 100644 tests/conf.d/error_log.ini create mode 100644 tests/conf.d/php-memory-limits.ini diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b4ed6cf0e..6fd9c7b03 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: true matrix: - php: [5.6, '7.0', 7.1, 7.2, 7.3, 7.4, '8.0', 8.1] + php: ['7.0', 7.1, 7.2, 7.3, 7.4, '8.0', 8.1] name: PHP ${{ matrix.php }} diff --git a/cli/Valet/Brew.php b/cli/Valet/Brew.php index a6a481e57..d9f02731f 100644 --- a/cli/Valet/Brew.php +++ b/cli/Valet/Brew.php @@ -15,12 +15,10 @@ class Brew 'php@7.2', 'php@7.1', 'php@7.0', - 'php@5.6', 'php73', 'php72', 'php71', 'php70', - 'php56', ]; const LATEST_PHP_VERSION = 'php@8.1'; diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 3d7bc74ae..30e827534 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -52,7 +52,7 @@ public function install() $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); - $this->updateConfiguration(); + $this->createConfigurationFiles(); $this->restart(); } @@ -70,12 +70,13 @@ public function uninstall() } /** - * Update the PHP FPM configuration. + * Create (or re-create) the PHP FPM configuration files. + * Writes FPM config file, pointing to the correct .sock file, and log and ini files * * @param string|null $phpVersion * @return void */ - public function updateConfiguration($phpVersion = null) + public function createConfigurationFiles($phpVersion = null) { info(sprintf('Updating PHP configuration%s...', $phpVersion ? ' for '.$phpVersion : '')); @@ -83,53 +84,31 @@ public function updateConfiguration($phpVersion = null) $this->files->ensureDirExists(dirname($fpmConfigFile), user()); - // rename (to disable) old FPM Pool configuration, regardless of whether it's a default config or one customized by an older Valet version - $oldFile = dirname($fpmConfigFile).'/www.conf'; - if (file_exists($oldFile)) { - rename($oldFile, $oldFile.'-backup'); - } - - if (false === strpos($fpmConfigFile, '5.6')) { - // since PHP 7 we can simply drop in a valet-specific fpm pool config, and not touch the default config - $contents = $this->files->get(__DIR__.'/../stubs/etc-phpfpm-valet.conf'); - $contents = str_replace(['VALET_USER', 'VALET_HOME_PATH'], [user(), VALET_HOME_PATH], $contents); - } else { - // for PHP 5 we must do a direct edit of the fpm pool config to switch it to Valet's needs - $contents = $this->files->get($fpmConfigFile); - $contents = preg_replace('/^user = .+$/m', 'user = '.user(), $contents); - $contents = preg_replace('/^group = .+$/m', 'group = staff', $contents); - $contents = preg_replace('/^listen = .+$/m', 'listen = '.VALET_HOME_PATH.'/valet.sock', $contents); - $contents = preg_replace('/^;?listen\.owner = .+$/m', 'listen.owner = '.user(), $contents); - $contents = preg_replace('/^;?listen\.group = .+$/m', 'listen.group = staff', $contents); - $contents = preg_replace('/^;?listen\.mode = .+$/m', 'listen.mode = 0777', $contents); - } - + // Drop in a valet-specific fpm pool config + $contents = $this->files->get(__DIR__.'/../stubs/etc-phpfpm-valet.conf'); + $contents = str_replace(['VALET_USER', 'VALET_HOME_PATH'], [user(), VALET_HOME_PATH], $contents); if ($phpVersion) { $contents = str_replace('valet.sock', $this->fpmSockName($phpVersion), $contents); } - $this->files->put($fpmConfigFile, $contents); + // Set log and ini files + $destDir = dirname(dirname($fpmConfigFile)) . '/conf.d'; + $this->files->ensureDirExists($destDir, user()); + $contents = $this->files->get(__DIR__.'/../stubs/php-memory-limits.ini'); - $destFile = dirname($fpmConfigFile); - $destFile = str_replace('/php-fpm.d', '', $destFile); - $destFile .= '/conf.d/php-memory-limits.ini'; - $this->files->ensureDirExists(dirname($destFile), user()); - $this->files->putAsUser($destFile, $contents); + $this->files->putAsUser($destDir.'/php-memory-limits.ini', $contents); $contents = $this->files->get(__DIR__.'/../stubs/etc-phpfpm-error_log.ini'); $contents = str_replace(['VALET_USER', 'VALET_HOME_PATH'], [user(), VALET_HOME_PATH], $contents); - $destFile = dirname($fpmConfigFile); - $destFile = str_replace('/php-fpm.d', '', $destFile); - $destFile .= '/conf.d/error_log.ini'; - $this->files->ensureDirExists(dirname($destFile), user()); - $this->files->putAsUser($destFile, $contents); + $this->files->putAsUser($destDir.'/error_log.ini', $contents); + $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); $this->files->touch(VALET_HOME_PATH.'/Log/php-fpm.log', user()); } /** - * Restart the PHP FPM process. + * Restart the PHP FPM process(es). * * @param string|null $phpVersion * @return void @@ -167,9 +146,7 @@ public function fpmConfigPath($phpVersion = null) $versionNormalized = $this->normalizePhpVersion($phpVersion === 'php' ? Brew::LATEST_PHP_VERSION : $phpVersion); $versionNormalized = preg_replace('~[^\d\.]~', '', $versionNormalized); - return $versionNormalized === '5.6' - ? BREW_PREFIX.'/etc/php/5.6/php-fpm.conf' - : BREW_PREFIX."/etc/php/${versionNormalized}/php-fpm.d/valet-fpm.conf"; + return BREW_PREFIX."/etc/php/${versionNormalized}/php-fpm.d/valet-fpm.conf"; } /** @@ -187,21 +164,17 @@ public function stopRunning() } /** - * Stop PHP, if a specific version isn't being used globally or by any sites. + * Stop a given PHP version, if a specific version isn't being used globally or by any sites. * * @param string|null $phpVersion * @return void */ - public function stopIfUnused($phpVersion) + public function stopIfUnused($phpVersion = null) { if (! $phpVersion) { return; } - if (strpos($phpVersion, 'php') === false) { - $phpVersion = 'php'.$phpVersion; - } - $phpVersion = $this->normalizePhpVersion($phpVersion); if (! in_array($phpVersion, $this->utilizedPhpVersions())) { @@ -210,38 +183,69 @@ public function stopIfUnused($phpVersion) } /** - * Use a specific version of php. + * Isolate a given directory to use a specific version of php. * + * @param string $directory * @param string $version - * @param bool $force - * @param string|null $directory - * @return string|void + * @return void */ - public function useVersion($version, $force = false, $directory = null) + public function isolateDirectoryToVersion($directory, $version) { - if ($directory) { - $site = $this->site->getSiteUrl($directory); - - if (! $site) { - throw new DomainException( - sprintf( - "The [%s] site could not be found in Valet's site list.", - $directory - ) - ); - } + if (!$site = $this->site->getSiteUrl($directory)) { + throw new DomainException("The [{$directory}] site could not be found in Valet's site list."); + } - if ($version == 'default') { // Remove isolation for this site - $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" - $this->site->removeIsolation($site); - $this->stopIfUnused($oldCustomPhpVersion); - $this->nginx->restart(); - info(sprintf('The site [%s] is now using the default PHP version.', $site)); + $this->brew->ensureInstalled($version, [], $this->taps); - return; - } + $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" + $this->createConfigurationFiles($version); + + $this->site->isolate($site, $this->fpmSockName($version), $version); + + $this->stopIfUnused($oldCustomPhpVersion); + $this->restart($version); + $this->nginx->restart(); + + info(sprintf('The site [%s] is now using %s.', $site, $version)); + } + + /** + * Remove PHP version isolation for a given directory + * + * @param string $directory + * @return void + */ + public function unIsolateDirectory($directory) + { + $site = $this->site->getSiteUrl($directory); + + if (!$site) { + throw new DomainException( + sprintf( + "The [%s] site could not be found in Valet's site list.", + $directory + ) + ); } + $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" + + $this->site->removeIsolation($site); + $this->stopIfUnused($oldCustomPhpVersion); + $this->nginx->restart(); + + info(sprintf('The site [%s] is now using the default PHP version.', $site)); + } + + /** + * Use a specific version of PHP globally. + * + * @param string $version + * @param bool $force + * @return string|void + */ + public function useVersion($version, $force = false) + { $version = $this->validateRequestedVersion($version); try { @@ -253,31 +257,14 @@ public function useVersion($version, $force = false, $directory = null) } catch (DomainException $e) { /* ignore thrown exception when no linked php is found */ } - if (! $this->brew->installed($version)) { - // Install the relevant formula if not already installed - $this->brew->ensureInstalled($version, [], $this->taps); - } - - if ($directory) { - $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($version)); - $this->updateConfiguration($version); - $this->site->installSiteConfig($site, $this->fpmSockName($version), $version); - - $this->stopIfUnused($oldCustomPhpVersion); - $this->restart($version); - $this->nginx->restart(); - info(sprintf('The site [%s] is now using %s.', $site, $version)); - - return; - } + $this->brew->ensureInstalled($version, [], $this->taps); // Unlink the current global PHP if there is one installed if ($this->brew->hasLinkedPhp()) { $linkedPhp = $this->brew->linkedPhp(); // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken - $this->updateConfiguration($linkedPhp); + $this->createConfigurationFiles($linkedPhp); // Update existing custom Nginx config files; if they're using the old or new PHP version, // update them to the new correct sock file location @@ -297,7 +284,6 @@ public function useVersion($version, $force = false, $directory = null) $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); - // ensure configuration is correct and start the linked version $this->install(); $newVersion = $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; @@ -311,17 +297,22 @@ public function useVersion($version, $force = false, $directory = null) } /** - * If passed php7.4 or php74 formats, normalize to php@7.4 format. + * If passed php7.4, or php74, 7.4, or 74 formats, normalize to php@7.4 format. */ public function normalizePhpVersion($version) { + // @todo There's probably a way to incorporate this into the regex + if (strpos($version, 'php') === false) { + $version = 'php' . $version; + } + return preg_replace('/(php)([0-9+])(?:.)?([0-9+])/i', '$1@$2.$3', $version); } /** * Validate the requested version to be sure we can support it. * - * @param $version + * @param string $version * @return string */ public function validateRequestedVersion($version) @@ -329,12 +320,7 @@ public function validateRequestedVersion($version) $version = $this->normalizePhpVersion($version); if (! $this->brew->supportedPhpVersions()->contains($version)) { - throw new DomainException( - sprintf( - 'Valet doesn\'t support PHP version: %s (try something like \'php@7.3\' instead)', - $version - ) - ); + throw new DomainException("Valet doesn't support PHP version: {$version} (try something like 'php@7.3' instead)"); } if (strpos($aliasedVersion = $this->brew->determineAliasedVersion($version), '@')) { @@ -342,10 +328,6 @@ public function validateRequestedVersion($version) } if ($version === 'php') { - if (strpos($aliasedVersion = $this->brew->determineAliasedVersion($version), '@')) { - return $aliasedVersion; - } - if ($this->brew->hasInstalledPhp()) { throw new DomainException('Brew is already using PHP '.PHP_VERSION.' as \'php\' in Homebrew. To use another version, please specify. eg: php@7.3'); } diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index be69085be..9075b34fe 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -704,9 +704,10 @@ public function buildSecureNginxServer($url, $siteConf = null) * @param string $phpVersion * @return void */ - public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) + public function isolate($valetSite, $fpmSockName, $phpVersion) { if ($this->files->exists($this->nginxPath($valetSite))) { + // Modify the existing config if it exists (likely because it's secured) $siteConf = $this->files->get($this->nginxPath($valetSite)); $siteConf = $this->replaceSockFile($siteConf, $fpmSockName, $phpVersion); } else { @@ -768,7 +769,7 @@ public function unsecure($url) // If the user had isolated the PHP version for this site, swap out .sock file if ($phpVersion) { - $this->installSiteConfig($url, "valet{$phpVersion}.sock", $phpVersion); + $this->isolate($url, "valet{$phpVersion}.sock", $phpVersion); } } diff --git a/cli/includes/compatibility.php b/cli/includes/compatibility.php index 4c2dc2a5d..86e57fe74 100644 --- a/cli/includes/compatibility.php +++ b/cli/includes/compatibility.php @@ -16,8 +16,8 @@ exit(1); } -if (version_compare(PHP_VERSION, '5.6.0', '<')) { - echo 'Valet requires PHP 5.6 or later.'; +if (version_compare(PHP_VERSION, '7.0', '<')) { + echo 'Valet requires PHP 7.0 or later.'; exit(1); } diff --git a/cli/valet.php b/cli/valet.php index f558f0be4..f279a1b85 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -498,14 +498,14 @@ $path = getcwd().'/.valetphprc'; $linkedVersion = Brew::linkedPhp(); if (! file_exists($path)) { - return info(sprintf('Valet is using %s.', $linkedVersion)); + return info("Valet is using {$linkedVersion}."); } $phpVersion = trim(file_get_contents($path)); - info('Found \''.$path.'\' specifying version: '.$phpVersion); + info("Found '{$path}' specifying version: {$phpVersion}"); if ($linkedVersion == $phpVersion) { - return info(sprintf('Valet is already using %s.', $linkedVersion)); + return info("Valet is already using {$linkedVersion}."); } } @@ -515,6 +515,25 @@ '--site' => 'Isolate PHP version of a specific valet site. e.g: --site=site.test', ]); + /** + * Allow the user to change the version of php valet uses to serve a given site. + */ + $app->command('isolate [site] [phpVersion] ', function ($site, $phpVersion) { + PhpFpm::isolateDirectoryToVersion($site, $phpVersion); + })->descriptions('Change the version of PHP used by valet to serve a given site', [ + 'site' => 'The valet site (e.g. site.test) you want to isolate to a given PHP version', + 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', + ]); + + /** + * Allow the user to un-do specifying the version of php valet uses to serve a given site. + */ + $app->command('unisolate [site] ', function ($site) { + PhpFpm::unIsolateDirectory($site); + })->descriptions('Stop customizing the version of PHP used by valet to serve a given site', [ + 'site' => 'The valet site (e.g. site.test) you want to un-isolate', + ]); + /** * Tail log file. */ diff --git a/composer.json b/composer.json index 1c870f32b..2cdc7a1b6 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ } }, "require": { - "php": "^5.6|^7.0|^8.0", + "php": "^7.0|^8.0", "illuminate/container": "~5.1|^6.0|^7.0|^8.0|^9.0", "mnapoli/silly": "^1.0", "symfony/process": "^3.0|^4.0|^5.0|^6.0", diff --git a/tests/BrewTest.php b/tests/BrewTest.php index a5f15304d..138f01805 100644 --- a/tests/BrewTest.php +++ b/tests/BrewTest.php @@ -93,24 +93,16 @@ public function test_has_installed_php_indicates_if_php_is_installed_via_brew() $brew = Mockery::mock(Brew::class.'[installedPhpFormulae]', [new CommandLine, new Filesystem]); $brew->shouldReceive('installedPhpFormulae')->andReturn(collect(['php@7.0'])); $this->assertTrue($brew->hasInstalledPhp()); - - $brew = Mockery::mock(Brew::class.'[installedPhpFormulae]', [new CommandLine, new Filesystem]); - $brew->shouldReceive('installedPhpFormulae')->andReturn(collect(['php@5.6'])); - $this->assertTrue($brew->hasInstalledPhp()); - - $brew = Mockery::mock(Brew::class.'[installedPhpFormulae]', [new CommandLine, new Filesystem]); - $brew->shouldReceive('installedPhpFormulae')->andReturn(collect(['php56'])); - $this->assertTrue($brew->hasInstalledPhp()); } public function test_tap_taps_the_given_homebrew_repository() { $cli = Mockery::mock(CommandLine::class); + $cli->shouldReceive('passthru')->once()->with('sudo -u "'.user().'" brew tap php@8.0'); $cli->shouldReceive('passthru')->once()->with('sudo -u "'.user().'" brew tap php@7.1'); $cli->shouldReceive('passthru')->once()->with('sudo -u "'.user().'" brew tap php@7.0'); - $cli->shouldReceive('passthru')->once()->with('sudo -u "'.user().'" brew tap php@5.6'); swap(CommandLine::class, $cli); - resolve(Brew::class)->tap('php@7.1', 'php@7.0', 'php@5.6'); + resolve(Brew::class)->tap('php@8.0', 'php@7.1', 'php@7.0'); } public function test_restart_restarts_the_service_using_homebrew_services() @@ -163,9 +155,6 @@ public function test_linked_php_returns_linked_php_formula_name() $files->shouldReceive('readLink')->once()->with(BREW_PREFIX.'/bin/php')->andReturn('/test/path/php72/7.2.9_2/test'); $this->assertSame('php@7.2', $getBrewMock($files)->linkedPhp()); - $files = Mockery::mock(Filesystem::class); - $files->shouldReceive('readLink')->once()->with(BREW_PREFIX.'/bin/php')->andReturn('/test/path/php56/test'); - $this->assertSame('php@5.6', $getBrewMock($files)->linkedPhp()); } public function test_linked_php_throws_exception_if_no_php_link() @@ -460,15 +449,15 @@ public function supportedPhpLinkPathProvider() 'php74', ], [ - '/test/path/php56/test', + '/test/path/php71/test', [ - 'path/php56/test', + 'path/php71/test', 'php', - '56', + '71', '', '', ], - 'php56', + 'php71', ], ]; } diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 79dafdf36..0250795aa 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -35,14 +35,14 @@ public function test_fpm_is_configured_with_the_correct_user_group_and_port() copy(__DIR__.'/files/fpm.conf', __DIR__.'/output/fpm.conf'); mkdir(__DIR__.'/output/conf.d'); copy(__DIR__.'/files/php-memory-limits.ini', __DIR__.'/output/conf.d/php-memory-limits.ini'); - resolve(StubForUpdatingFpmConfigFiles::class)->updateConfiguration(); + resolve(StubForUpdatingFpmConfigFiles::class)->createConfigurationFiles(); $contents = file_get_contents(__DIR__.'/output/fpm.conf'); $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); $this->assertStringContainsString("\ngroup = staff", $contents); $this->assertStringContainsString("\nlisten = ".VALET_HOME_PATH.'/valet.sock', $contents); // Passing specific version will change the .sock file - resolve(StubForUpdatingFpmConfigFiles::class)->updateConfiguration('php@7.2'); + resolve(StubForUpdatingFpmConfigFiles::class)->createConfigurationFiles('php@7.2'); $contents = file_get_contents(__DIR__.'/output/fpm.conf'); $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); $this->assertStringContainsString("\ngroup = staff", $contents); @@ -229,7 +229,7 @@ public function test_stopRunning_will_pass_filtered_result_of_getRunningServices ->andReturn(collect([ 'php7.2', 'php@7.3', - 'php56', + 'php71', 'php', 'nginx', 'somethingelse', @@ -237,7 +237,7 @@ public function test_stopRunning_will_pass_filtered_result_of_getRunningServices $brewMock->shouldReceive('stopService')->once()->with([ 'php7.2', 'php@7.3', - 'php56', + 'php71', 'php', ]); @@ -264,7 +264,7 @@ public function test_use_version_will_convert_passed_php_version() $brewMock->shouldReceive('supportedPhpVersions')->twice()->andReturn(collect([ 'php@7.2', - 'php@5.6', + 'php@7.1', ])); $brewMock->shouldReceive('hasLinkedPhp')->andReturn(false); $brewMock->shouldReceive('ensureInstalled')->with('php@7.2', [], $phpFpmMock->taps); @@ -318,12 +318,12 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $cliMock->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet*.sock')->once(); $fileSystemMock->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock')->once(); - $phpFpmMock->shouldReceive('updateConfiguration')->with('php@7.1')->once(); + $phpFpmMock->shouldReceive('createConfigurationFiles')->with('php@7.1')->once(); $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate')->withArgs(['php@7.2', 'php@7.1'])->once(); $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', - 'php@5.6', + 'php@7.1', ])); $brewMock->shouldReceive('hasLinkedPhp')->andReturn(true); @@ -343,7 +343,7 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $this->assertSame('php@7.2', $phpFpmMock->useVersion('php@7.2')); } - public function test_use_version_with_site_parameter_will_isolate_a_site() + public function test_isolate_will_isolate_a_site() { $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); @@ -360,20 +360,20 @@ public function test_use_version_with_site_parameter_will_isolate_a_site() $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', - 'php@5.6', + 'php@7.1', ])); $brewMock->shouldReceive('ensureInstalled')->with('php@7.2', [], $phpFpmMock->taps); $brewMock->shouldReceive('installed')->with('php@7.2'); $brewMock->shouldReceive('determineAliasedVersion')->with('php@7.2')->andReturn('php@7.2'); - $brewMock->shouldReceive('linkedPhp')->once(); + // $brewMock->shouldReceive('linkedPhp')->once(); $siteMock->shouldReceive('getSiteUrl')->with('test')->andReturn('test.test'); - $siteMock->shouldReceive('installSiteConfig')->withArgs(['test.test', 'valet72.sock', 'php@7.2']); + $siteMock->shouldReceive('isolate')->withArgs(['test.test', 'valet72.sock', 'php@7.2']); $siteMock->shouldReceive('customPhpVersion')->with('test.test')->andReturn('72'); $phpFpmMock->shouldReceive('stopIfUnused')->with('72')->once(); - $phpFpmMock->shouldReceive('updateConfiguration')->with('php@7.2')->once(); + $phpFpmMock->shouldReceive('createConfigurationFiles')->with('php@7.2')->once(); $phpFpmMock->shouldReceive('restart')->with('php@7.2')->once(); $nginxMock->shouldReceive('restart'); @@ -386,10 +386,10 @@ public function test_use_version_with_site_parameter_will_isolate_a_site() $phpFpmMock->shouldNotReceive('install'); $phpFpmMock->shouldNotReceive('updateConfigurationForGlobalUpdate'); - $this->assertSame(null, $phpFpmMock->useVersion('php@7.2', false, 'test')); + $this->assertSame(null, $phpFpmMock->isolateDirectoryToVersion('test', 'php@7.2')); } - public function test_use_version_can_remove_isolation_for_a_site() + public function test_un_isolate_can_remove_isolation_for_a_site() { $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); @@ -409,10 +409,10 @@ public function test_use_version_can_remove_isolation_for_a_site() $phpFpmMock->shouldReceive('stopIfUnused')->with('74'); $nginxMock->shouldReceive('restart'); - $this->assertSame(null, $phpFpmMock->useVersion('default', false, 'test')); + $this->assertSame(null, $phpFpmMock->unIsolateDirectory('test')); } - public function test_use_version_will_throw_if_site_is_not_parked_or_linked() + public function test_isolate_will_throw_if_site_is_not_parked_or_linked() { $siteMock = Mockery::mock(Site::class); @@ -430,7 +430,7 @@ public function test_use_version_will_throw_if_site_is_not_parked_or_linked() $siteMock->shouldReceive('getSiteUrl'); - $this->assertSame(null, $phpFpmMock->useVersion('default', false, 'test')); + $this->assertSame(null, $phpFpmMock->isolateDirectoryToVersion('test', 'php@8.1')); } } diff --git a/tests/SiteTest.php b/tests/SiteTest.php index 7ef268b63..a8a765b16 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -630,12 +630,12 @@ public function test_isolation_will_persist_when_removing_ssl_certificate() // If a site has an isolated PHP version, there should still be a custom nginx site config $siteMock->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once(); - $siteMock->shouldReceive('installSiteConfig')->withArgs(['site1.test', 'valet73.sock', '73'])->once(); + $siteMock->shouldReceive('isolate')->withArgs(['site1.test', 'valet73.sock', '73'])->once(); resolve(Site::class)->unsecure('site1.test'); // If a site doesn't have an isolated PHP version, there should no longer be a custom nginx site config $siteMock->shouldReceive('customPhpVersion')->with('site2.test')->andReturn(null)->once(); - $siteMock->shouldNotReceive('installSiteConfig'); + $siteMock->shouldNotReceive('isolate'); resolve(Site::class)->unsecure('site2.test'); } @@ -668,7 +668,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() '# Valet isolated PHP version : php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', ]); - $siteMock->installSiteConfig('site1.test', 'valet80.sock', 'php@8.0'); + $siteMock->isolate('site1.test', 'valet80.sock', 'php@8.0'); // When no Nginx file exists, it will create a new config file from the template $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site2.test'))->andReturn(false); @@ -688,7 +688,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() }), ]); - $siteMock->installSiteConfig('site2.test', 'valet80.sock', 'php@8.0'); + $siteMock->isolate('site2.test', 'valet80.sock', 'php@8.0'); } public function test_it_removes_isolation() diff --git a/tests/conf.d/error_log.ini b/tests/conf.d/error_log.ini new file mode 100644 index 000000000..8a2d2d409 --- /dev/null +++ b/tests/conf.d/error_log.ini @@ -0,0 +1,5 @@ +; php-fpm error logging directives + +error_log="/Users/mattstauffer/.config/valet/Log/php-fpm.log" +log_errors=on +log_level=debug diff --git a/tests/conf.d/php-memory-limits.ini b/tests/conf.d/php-memory-limits.ini new file mode 100644 index 000000000..b0447baf2 --- /dev/null +++ b/tests/conf.d/php-memory-limits.ini @@ -0,0 +1,10 @@ +; Max memory per instance +memory_limit = 512M + +;The maximum size of an uploaded file. +upload_max_filesize = 512M + +; Sets max size of post data allowed. +; Changes to this will also need to be reflected in Nginx with client_max_body_size +; This setting also affects file upload. To upload large files, this value must be larger than upload_max_filesize +post_max_size = 512M From e797774ade6ce46ce2b5a30935b964269bfd8ec7 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sat, 12 Mar 2022 05:06:07 +0000 Subject: [PATCH 13/41] Apply fixes from StyleCI --- cli/Valet/PhpFpm.php | 14 +++++++------- tests/BrewTest.php | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 30e827534..326f2e68a 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -71,7 +71,7 @@ public function uninstall() /** * Create (or re-create) the PHP FPM configuration files. - * Writes FPM config file, pointing to the correct .sock file, and log and ini files + * Writes FPM config file, pointing to the correct .sock file, and log and ini files. * * @param string|null $phpVersion * @return void @@ -93,7 +93,7 @@ public function createConfigurationFiles($phpVersion = null) $this->files->put($fpmConfigFile, $contents); // Set log and ini files - $destDir = dirname(dirname($fpmConfigFile)) . '/conf.d'; + $destDir = dirname(dirname($fpmConfigFile)).'/conf.d'; $this->files->ensureDirExists($destDir, user()); $contents = $this->files->get(__DIR__.'/../stubs/php-memory-limits.ini'); @@ -191,7 +191,7 @@ public function stopIfUnused($phpVersion = null) */ public function isolateDirectoryToVersion($directory, $version) { - if (!$site = $this->site->getSiteUrl($directory)) { + if (! $site = $this->site->getSiteUrl($directory)) { throw new DomainException("The [{$directory}] site could not be found in Valet's site list."); } @@ -210,7 +210,7 @@ public function isolateDirectoryToVersion($directory, $version) } /** - * Remove PHP version isolation for a given directory + * Remove PHP version isolation for a given directory. * * @param string $directory * @return void @@ -219,7 +219,7 @@ public function unIsolateDirectory($directory) { $site = $this->site->getSiteUrl($directory); - if (!$site) { + if (! $site) { throw new DomainException( sprintf( "The [%s] site could not be found in Valet's site list.", @@ -303,7 +303,7 @@ public function normalizePhpVersion($version) { // @todo There's probably a way to incorporate this into the regex if (strpos($version, 'php') === false) { - $version = 'php' . $version; + $version = 'php'.$version; } return preg_replace('/(php)([0-9+])(?:.)?([0-9+])/i', '$1@$2.$3', $version); @@ -312,7 +312,7 @@ public function normalizePhpVersion($version) /** * Validate the requested version to be sure we can support it. * - * @param string $version + * @param string $version * @return string */ public function validateRequestedVersion($version) diff --git a/tests/BrewTest.php b/tests/BrewTest.php index 138f01805..f2886277f 100644 --- a/tests/BrewTest.php +++ b/tests/BrewTest.php @@ -154,7 +154,6 @@ public function test_linked_php_returns_linked_php_formula_name() $files = Mockery::mock(Filesystem::class); $files->shouldReceive('readLink')->once()->with(BREW_PREFIX.'/bin/php')->andReturn('/test/path/php72/7.2.9_2/test'); $this->assertSame('php@7.2', $getBrewMock($files)->linkedPhp()); - } public function test_linked_php_throws_exception_if_no_php_link() From 33c797f9ef15db2b0686657fe252e11796045df2 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sat, 12 Mar 2022 00:20:40 -0500 Subject: [PATCH 14/41] Drop need to pass sock to isolate command --- cli/Valet/PhpFpm.php | 16 +++++++++------- cli/Valet/Site.php | 10 ++++++---- tests/PhpFpmTest.php | 2 +- tests/SiteTest.php | 6 +++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 30e827534..a756466dc 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -88,7 +88,7 @@ public function createConfigurationFiles($phpVersion = null) $contents = $this->files->get(__DIR__.'/../stubs/etc-phpfpm-valet.conf'); $contents = str_replace(['VALET_USER', 'VALET_HOME_PATH'], [user(), VALET_HOME_PATH], $contents); if ($phpVersion) { - $contents = str_replace('valet.sock', $this->fpmSockName($phpVersion), $contents); + $contents = str_replace('valet.sock', self::fpmSockName($phpVersion), $contents); } $this->files->put($fpmConfigFile, $contents); @@ -195,12 +195,14 @@ public function isolateDirectoryToVersion($directory, $version) throw new DomainException("The [{$directory}] site could not be found in Valet's site list."); } + $version = $this->validateRequestedVersion($version); + $this->brew->ensureInstalled($version, [], $this->taps); $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" $this->createConfigurationFiles($version); - $this->site->isolate($site, $this->fpmSockName($version), $version); + $this->site->isolate($site, $version); $this->stopIfUnused($oldCustomPhpVersion); $this->restart($version); @@ -342,7 +344,7 @@ public function validateRequestedVersion($version) * @param string|null $phpVersion * @return string */ - public function fpmSockName($phpVersion = null) + public static function fpmSockName($phpVersion = null) { $versionInteger = preg_replace('~[^\d]~', '', $phpVersion); @@ -373,12 +375,12 @@ public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersio return; } - if (strpos($content, $this->fpmSockName($newPhpVersion)) !== false) { + if (strpos($content, self::fpmSockName($newPhpVersion)) !== false) { info(sprintf('Updating site %s to keep using version: %s', $file, $newPhpVersion)); - $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace($this->fpmSockName($newPhpVersion), 'valet.sock', $content)); + $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace(self::fpmSockName($newPhpVersion), 'valet.sock', $content)); } elseif (strpos($content, 'valet.sock') !== false) { info(sprintf('Updating site %s to keep using version: %s', $file, $oldPhpVersion)); - $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace('valet.sock', $this->fpmSockName($oldPhpVersion), $content)); + $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace('valet.sock', self::fpmSockName($oldPhpVersion), $content)); } }); } @@ -392,7 +394,7 @@ public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersio public function utilizedPhpVersions() { $fpmSockFiles = $this->brew->supportedPhpVersions()->map(function ($version) { - return $this->fpmSockName($this->normalizePhpVersion($version)); + return self::fpmSockName($this->normalizePhpVersion($version)); })->unique(); return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 9075b34fe..4f94c2072 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -697,15 +697,17 @@ public function buildSecureNginxServer($url, $siteConf = null) } /** - * Build the Nginx server configuration for the given Valet site. + * Create new nginx config or modify existing nginx config to isolate this site + * to a custom version of PHP. * * @param string $valetSite - * @param string $fpmSockName * @param string $phpVersion * @return void */ - public function isolate($valetSite, $fpmSockName, $phpVersion) + public function isolate($valetSite, $phpVersion) { + $fpmSockName = PhpFpm::fpmSockName($phpVersion); + if ($this->files->exists($this->nginxPath($valetSite))) { // Modify the existing config if it exists (likely because it's secured) $siteConf = $this->files->get($this->nginxPath($valetSite)); @@ -769,7 +771,7 @@ public function unsecure($url) // If the user had isolated the PHP version for this site, swap out .sock file if ($phpVersion) { - $this->isolate($url, "valet{$phpVersion}.sock", $phpVersion); + $this->isolate($url, $phpVersion); } } diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 0250795aa..436672a41 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -369,7 +369,7 @@ public function test_isolate_will_isolate_a_site() // $brewMock->shouldReceive('linkedPhp')->once(); $siteMock->shouldReceive('getSiteUrl')->with('test')->andReturn('test.test'); - $siteMock->shouldReceive('isolate')->withArgs(['test.test', 'valet72.sock', 'php@7.2']); + $siteMock->shouldReceive('isolate')->withArgs(['test.test', 'php@7.2']); $siteMock->shouldReceive('customPhpVersion')->with('test.test')->andReturn('72'); $phpFpmMock->shouldReceive('stopIfUnused')->with('72')->once(); diff --git a/tests/SiteTest.php b/tests/SiteTest.php index a8a765b16..7db70ab5a 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -630,7 +630,7 @@ public function test_isolation_will_persist_when_removing_ssl_certificate() // If a site has an isolated PHP version, there should still be a custom nginx site config $siteMock->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once(); - $siteMock->shouldReceive('isolate')->withArgs(['site1.test', 'valet73.sock', '73'])->once(); + $siteMock->shouldReceive('isolate')->withArgs(['site1.test', '73'])->once(); resolve(Site::class)->unsecure('site1.test'); // If a site doesn't have an isolated PHP version, there should no longer be a custom nginx site config @@ -668,7 +668,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() '# Valet isolated PHP version : php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', ]); - $siteMock->isolate('site1.test', 'valet80.sock', 'php@8.0'); + $siteMock->isolate('site1.test', 'php@8.0'); // When no Nginx file exists, it will create a new config file from the template $files->shouldReceive('exists')->once()->with($siteMock->nginxPath('site2.test'))->andReturn(false); @@ -688,7 +688,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() }), ]); - $siteMock->isolate('site2.test', 'valet80.sock', 'php@8.0'); + $siteMock->isolate('site2.test', 'php@8.0'); } public function test_it_removes_isolation() From 55c7dcb99d8da03f2a91f91f0deac4d525cf7b47 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sat, 12 Mar 2022 00:23:00 -0500 Subject: [PATCH 15/41] Move string concat to one line --- cli/Valet/PhpFpm.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index a756466dc..661cdd3e7 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -222,12 +222,7 @@ public function unIsolateDirectory($directory) $site = $this->site->getSiteUrl($directory); if (!$site) { - throw new DomainException( - sprintf( - "The [%s] site could not be found in Valet's site list.", - $directory - ) - ); + throw new DomainException("The [{$directory}] site could not be found in Valet's site list."); } $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" From 0a677e2d53b9bdc055405a36640201abcdc071e3 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sat, 12 Mar 2022 05:23:47 +0000 Subject: [PATCH 16/41] Apply fixes from StyleCI --- cli/Valet/PhpFpm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index e35c5bb27..557fa6a0a 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -221,7 +221,7 @@ public function unIsolateDirectory($directory) { $site = $this->site->getSiteUrl($directory); - if (!$site) { + if (! $site) { throw new DomainException("The [{$directory}] site could not be found in Valet's site list."); } From c5903eed63304468f53e8863abb62f67f4d881e9 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sat, 12 Mar 2022 00:24:53 -0500 Subject: [PATCH 17/41] Drop config files from new test layout --- .gitignore | 1 + tests/conf.d/error_log.ini | 5 ----- tests/conf.d/php-memory-limits.ini | 10 ---------- 3 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 tests/conf.d/error_log.ini delete mode 100644 tests/conf.d/php-memory-limits.ini diff --git a/.gitignore b/.gitignore index 737bb2c64..8277f6c32 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.lock error.log .idea .phpunit.result.cache +tests/conf.d diff --git a/tests/conf.d/error_log.ini b/tests/conf.d/error_log.ini deleted file mode 100644 index 8a2d2d409..000000000 --- a/tests/conf.d/error_log.ini +++ /dev/null @@ -1,5 +0,0 @@ -; php-fpm error logging directives - -error_log="/Users/mattstauffer/.config/valet/Log/php-fpm.log" -log_errors=on -log_level=debug diff --git a/tests/conf.d/php-memory-limits.ini b/tests/conf.d/php-memory-limits.ini deleted file mode 100644 index b0447baf2..000000000 --- a/tests/conf.d/php-memory-limits.ini +++ /dev/null @@ -1,10 +0,0 @@ -; Max memory per instance -memory_limit = 512M - -;The maximum size of an uploaded file. -upload_max_filesize = 512M - -; Sets max size of post data allowed. -; Changes to this will also need to be reflected in Nginx with client_max_body_size -; This setting also affects file upload. To upload large files, this value must be larger than upload_max_filesize -post_max_size = 512M From 592354877d080f9424a8b4bb7d62ec75d8906798 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sat, 12 Mar 2022 22:28:25 -0500 Subject: [PATCH 18/41] Rename isolateDirectory --- cli/Valet/PhpFpm.php | 9 ++++++--- cli/valet.php | 2 +- tests/PhpFpmTest.php | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 557fa6a0a..ec3cc2ebb 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -71,6 +71,7 @@ public function uninstall() /** * Create (or re-create) the PHP FPM configuration files. + * * Writes FPM config file, pointing to the correct .sock file, and log and ini files. * * @param string|null $phpVersion @@ -183,13 +184,13 @@ public function stopIfUnused($phpVersion = null) } /** - * Isolate a given directory to use a specific version of php. + * Isolate a given directory to use a specific version of PHP. * * @param string $directory * @param string $version * @return void */ - public function isolateDirectoryToVersion($directory, $version) + public function isolateDirectory($directory, $version) { if (! $site = $this->site->getSiteUrl($directory)) { throw new DomainException("The [{$directory}] site could not be found in Valet's site list."); @@ -200,6 +201,7 @@ public function isolateDirectoryToVersion($directory, $version) $this->brew->ensureInstalled($version, [], $this->taps); $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($oldCustomPhpVersion)); $this->createConfigurationFiles($version); $this->site->isolate($site, $version); @@ -298,7 +300,6 @@ public function useVersion($version, $force = false) */ public function normalizePhpVersion($version) { - // @todo There's probably a way to incorporate this into the regex if (strpos($version, 'php') === false) { $version = 'php'.$version; } @@ -348,8 +349,10 @@ public static function fpmSockName($phpVersion = null) /** * Update all existing Nginx files when running a global PHP version update. + * * If a given file is pointing to `valet.sock`, it's targeting the old global PHP version; * update it to point to the new custom sock file for that version. + * * If a given file is pointing the custom sock file for the new global version, that new * version will now be hosted at `valet.sock`, so update the config file to point to that instead. * diff --git a/cli/valet.php b/cli/valet.php index f279a1b85..7679fa372 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -519,7 +519,7 @@ * Allow the user to change the version of php valet uses to serve a given site. */ $app->command('isolate [site] [phpVersion] ', function ($site, $phpVersion) { - PhpFpm::isolateDirectoryToVersion($site, $phpVersion); + PhpFpm::isolateDirectory($site, $phpVersion); })->descriptions('Change the version of PHP used by valet to serve a given site', [ 'site' => 'The valet site (e.g. site.test) you want to isolate to a given PHP version', 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 436672a41..d169731ef 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -386,7 +386,7 @@ public function test_isolate_will_isolate_a_site() $phpFpmMock->shouldNotReceive('install'); $phpFpmMock->shouldNotReceive('updateConfigurationForGlobalUpdate'); - $this->assertSame(null, $phpFpmMock->isolateDirectoryToVersion('test', 'php@7.2')); + $this->assertSame(null, $phpFpmMock->isolateDirectory('test', 'php@7.2')); } public function test_un_isolate_can_remove_isolation_for_a_site() @@ -430,7 +430,7 @@ public function test_isolate_will_throw_if_site_is_not_parked_or_linked() $siteMock->shouldReceive('getSiteUrl'); - $this->assertSame(null, $phpFpmMock->isolateDirectoryToVersion('test', 'php@8.1')); + $this->assertSame(null, $phpFpmMock->isolateDirectory('test', 'php@8.1')); } } From 3570c748a092d3881e23bb168517ce4b268ee6aa Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sat, 12 Mar 2022 22:37:57 -0500 Subject: [PATCH 19/41] Clean up PhpFPM readability --- cli/Valet/PhpFpm.php | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index ec3cc2ebb..fe91ed10b 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -79,37 +79,46 @@ public function uninstall() */ public function createConfigurationFiles($phpVersion = null) { - info(sprintf('Updating PHP configuration%s...', $phpVersion ? ' for '.$phpVersion : '')); + info(sprintf('Updating PHP configuration%s...', ($phpVersion ? ' for '.$phpVersion : ''))); $fpmConfigFile = $this->fpmConfigPath($phpVersion); $this->files->ensureDirExists(dirname($fpmConfigFile), user()); - // Drop in a valet-specific fpm pool config - $contents = $this->files->get(__DIR__.'/../stubs/etc-phpfpm-valet.conf'); - $contents = str_replace(['VALET_USER', 'VALET_HOME_PATH'], [user(), VALET_HOME_PATH], $contents); + // Create FPM Config File from stub + $contents = str_replace( + ['VALET_USER', 'VALET_HOME_PATH'], + [user(), VALET_HOME_PATH], + $this->files->get(__DIR__.'/../stubs/etc-phpfpm-valet.conf') + ); if ($phpVersion) { $contents = str_replace('valet.sock', self::fpmSockName($phpVersion), $contents); } $this->files->put($fpmConfigFile, $contents); - // Set log and ini files + // Create other config files from stubs $destDir = dirname(dirname($fpmConfigFile)).'/conf.d'; $this->files->ensureDirExists($destDir, user()); - $contents = $this->files->get(__DIR__.'/../stubs/php-memory-limits.ini'); - $this->files->putAsUser($destDir.'/php-memory-limits.ini', $contents); + $this->files->putAsUser( + $destDir.'/php-memory-limits.ini', + $this->files->get(__DIR__.'/../stubs/php-memory-limits.ini') + ); - $contents = $this->files->get(__DIR__.'/../stubs/etc-phpfpm-error_log.ini'); - $contents = str_replace(['VALET_USER', 'VALET_HOME_PATH'], [user(), VALET_HOME_PATH], $contents); + $contents = str_replace( + ['VALET_USER', 'VALET_HOME_PATH'], + [user(), VALET_HOME_PATH], + $this->files->get(__DIR__.'/../stubs/etc-phpfpm-error_log.ini') + ); $this->files->putAsUser($destDir.'/error_log.ini', $contents); + // Create log directory and file $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); $this->files->touch(VALET_HOME_PATH.'/Log/php-fpm.log', user()); } /** - * Restart the PHP FPM process(es). + * Restart the PHP FPM process (if one specified) or processes (if none specified). * * @param string|null $phpVersion * @return void @@ -151,7 +160,7 @@ public function fpmConfigPath($phpVersion = null) } /** - * Only stop running php services. + * Stop only the running php services. */ public function stopRunning() { @@ -165,7 +174,7 @@ public function stopRunning() } /** - * Stop a given PHP version, if a specific version isn't being used globally or by any sites. + * Stop a given PHP version, if that specific version isn't being used globally or by any sites. * * @param string|null $phpVersion * @return void From 51742b3795bf4d05e3a49abf7202f72d07b51473 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sat, 12 Mar 2022 23:29:01 -0500 Subject: [PATCH 20/41] Make primary valet.sock a symlink to an existing version --- cli/Valet/PhpFpm.php | 80 +++++++++++++------------------------------- cli/Valet/Site.php | 13 ++++--- tests/PhpFpmTest.php | 16 ++++----- tests/SiteTest.php | 12 +++---- 4 files changed, 41 insertions(+), 80 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index fe91ed10b..b1910508a 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -52,7 +52,9 @@ public function install() $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); - $this->createConfigurationFiles(); + $phpVersion = $this->brew->linkedPhp(); + $this->createConfigurationFiles($phpVersion); + $this->symlinkPrimaryValetSock($phpVersion); $this->restart(); } @@ -74,12 +76,12 @@ public function uninstall() * * Writes FPM config file, pointing to the correct .sock file, and log and ini files. * - * @param string|null $phpVersion + * @param string $phpVersion * @return void */ - public function createConfigurationFiles($phpVersion = null) + public function createConfigurationFiles($phpVersion) { - info(sprintf('Updating PHP configuration%s...', ($phpVersion ? ' for '.$phpVersion : ''))); + info("Updating PHP configuration for {$phpVersion}..."); $fpmConfigFile = $this->fpmConfigPath($phpVersion); @@ -87,13 +89,10 @@ public function createConfigurationFiles($phpVersion = null) // Create FPM Config File from stub $contents = str_replace( - ['VALET_USER', 'VALET_HOME_PATH'], - [user(), VALET_HOME_PATH], + ['VALET_USER', 'VALET_HOME_PATH', 'valet.sock'], + [user(), VALET_HOME_PATH, self::fpmSockName($phpVersion)], $this->files->get(__DIR__.'/../stubs/etc-phpfpm-valet.conf') ); - if ($phpVersion) { - $contents = str_replace('valet.sock', self::fpmSockName($phpVersion), $contents); - } $this->files->put($fpmConfigFile, $contents); // Create other config files from stubs @@ -210,7 +209,6 @@ public function isolateDirectory($directory, $version) $this->brew->ensureInstalled($version, [], $this->taps); $oldCustomPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($oldCustomPhpVersion)); $this->createConfigurationFiles($version); $this->site->isolate($site, $version); @@ -269,15 +267,6 @@ public function useVersion($version, $force = false) // Unlink the current global PHP if there is one installed if ($this->brew->hasLinkedPhp()) { - $linkedPhp = $this->brew->linkedPhp(); - - // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken - $this->createConfigurationFiles($linkedPhp); - - // Update existing custom Nginx config files; if they're using the old or new PHP version, - // update them to the new correct sock file location - $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); - $currentVersion = $this->brew->getLinkedPhpFormula(); info(sprintf('Unlinking current version: %s', $currentVersion)); $this->brew->unlink($currentVersion); @@ -288,9 +277,9 @@ public function useVersion($version, $force = false) $this->stopRunning(); - // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts + // Remove valet.sock $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet.sock'); $this->install(); @@ -304,6 +293,19 @@ public function useVersion($version, $force = false) return $newVersion; } + /** + * Symlink (Capistrano-style) a given Valet.sock file to be the primary valet.sock. + * + * @todo write tests + * + * @param string $phpVersion + * @return void + */ + public function symlinkPrimaryValetSock($phpVersion) + { + $this->files->symlink($this->fpmSockName($phpVersion), VALET_HOME_PATH.'/valet.sock'); + } + /** * If passed php7.4, or php74, 7.4, or 74 formats, normalize to php@7.4 format. */ @@ -356,42 +358,6 @@ public static function fpmSockName($phpVersion = null) return "valet{$versionInteger}.sock"; } - /** - * Update all existing Nginx files when running a global PHP version update. - * - * If a given file is pointing to `valet.sock`, it's targeting the old global PHP version; - * update it to point to the new custom sock file for that version. - * - * If a given file is pointing the custom sock file for the new global version, that new - * version will now be hosted at `valet.sock`, so update the config file to point to that instead. - * - * @param string $newPhpVersion - * @param string $oldPhpVersion - * @return void - */ - public function updateConfigurationForGlobalUpdate($newPhpVersion, $oldPhpVersion) - { - collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) - ->reject(function ($file) { - return starts_with($file, '.'); - }) - ->each(function ($file) use ($newPhpVersion, $oldPhpVersion) { - $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); - - if (! starts_with($content, '# Valet isolated PHP version')) { - return; - } - - if (strpos($content, self::fpmSockName($newPhpVersion)) !== false) { - info(sprintf('Updating site %s to keep using version: %s', $file, $newPhpVersion)); - $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace(self::fpmSockName($newPhpVersion), 'valet.sock', $content)); - } elseif (strpos($content, 'valet.sock') !== false) { - info(sprintf('Updating site %s to keep using version: %s', $file, $oldPhpVersion)); - $this->files->put(VALET_HOME_PATH.'/Nginx/'.$file, str_replace('valet.sock', self::fpmSockName($oldPhpVersion), $content)); - } - }); - } - /** * Get a list including the global PHP version and allPHP versions currently serving "isolated sites" (sites with * custom Nginx configs pointing them to a specific PHP version). diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 4f94c2072..71519924d 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -517,7 +517,7 @@ public function secure($url, $siteConf = null, $certificateExpireInDays = 396, $ // If the user had isolated the PHP version for this site, swap out .sock file if ($phpVersion) { - $siteConf = $this->replaceSockFile($siteConf, "valet{$phpVersion}.sock", $phpVersion); + $siteConf = $this->replaceSockFile($siteConf, $phpVersion); } $this->files->putAsUser($this->nginxPath($url), $siteConf); @@ -706,16 +706,14 @@ public function buildSecureNginxServer($url, $siteConf = null) */ public function isolate($valetSite, $phpVersion) { - $fpmSockName = PhpFpm::fpmSockName($phpVersion); - if ($this->files->exists($this->nginxPath($valetSite))) { // Modify the existing config if it exists (likely because it's secured) $siteConf = $this->files->get($this->nginxPath($valetSite)); - $siteConf = $this->replaceSockFile($siteConf, $fpmSockName, $phpVersion); + $siteConf = $this->replaceSockFile($siteConf, $phpVersion); } else { $siteConf = str_replace( ['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX', 'VALET_SITE', 'VALET_PHP_FPM_SOCKET', 'VALET_ISOLATED_PHP_VERSION'], - [VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $valetSite, $fpmSockName, $phpVersion], + [VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $valetSite, PhpFpm::fpmSockName($phpVersion), $phpVersion], $this->replaceLoopback($this->files->get(__DIR__.'/../stubs/site.valet.conf')) ); } @@ -1096,12 +1094,13 @@ public function customPhpVersion($url) * Replace .sock file in an Nginx site configuration file contents. * * @param string $siteConf - * @param string $sockFile * @param string $phpVersion * @return string */ - public function replaceSockFile($siteConf, $sockFile, $phpVersion) + public function replaceSockFile($siteConf, $phpVersion) { + $sockFile = PhpFpm::fpmSockName($phpVersion); + $siteConf = preg_replace('/valet[0-9]*.sock/', $sockFile, $siteConf); $siteConf = preg_replace('/# Valet isolated PHP version.*\n/', '', $siteConf); // Remove `Valet isolated PHP version` line from config diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index d169731ef..ecfa5c136 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -35,13 +35,7 @@ public function test_fpm_is_configured_with_the_correct_user_group_and_port() copy(__DIR__.'/files/fpm.conf', __DIR__.'/output/fpm.conf'); mkdir(__DIR__.'/output/conf.d'); copy(__DIR__.'/files/php-memory-limits.ini', __DIR__.'/output/conf.d/php-memory-limits.ini'); - resolve(StubForUpdatingFpmConfigFiles::class)->createConfigurationFiles(); - $contents = file_get_contents(__DIR__.'/output/fpm.conf'); - $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); - $this->assertStringContainsString("\ngroup = staff", $contents); - $this->assertStringContainsString("\nlisten = ".VALET_HOME_PATH.'/valet.sock', $contents); - // Passing specific version will change the .sock file resolve(StubForUpdatingFpmConfigFiles::class)->createConfigurationFiles('php@7.2'); $contents = file_get_contents(__DIR__.'/output/fpm.conf'); $this->assertStringContainsString(sprintf("\nuser = %s", user()), $contents); @@ -113,6 +107,8 @@ public function test_utilized_php_versions() public function test_global_php_version_update_will_swap_socks() { + $this->markTestIncomplete('Needs deleting or refactoring'); + $fileSystemMock = Mockery::mock(Filesystem::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ @@ -315,11 +311,11 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal ])->makePartial(); $phpFpmMock->shouldReceive('install'); - $cliMock->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet*.sock')->once(); + $cliMock->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet.sock')->once(); $fileSystemMock->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock')->once(); - $phpFpmMock->shouldReceive('createConfigurationFiles')->with('php@7.1')->once(); - $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate')->withArgs(['php@7.2', 'php@7.1'])->once(); + // $phpFpmMock->shouldReceive('createConfigurationFiles')->with('php@7.1')->once(); + // $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate')->withArgs(['php@7.2', 'php@7.1'])->once(); $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', @@ -384,7 +380,7 @@ public function test_isolate_will_isolate_a_site() $brewMock->shouldNotReceive('unlink'); $phpFpmMock->shouldNotReceive('stopRunning'); $phpFpmMock->shouldNotReceive('install'); - $phpFpmMock->shouldNotReceive('updateConfigurationForGlobalUpdate'); + // $phpFpmMock->shouldNotReceive('updateConfigurationForGlobalUpdate'); $this->assertSame(null, $phpFpmMock->isolateDirectory('test', 'php@7.2')); } diff --git a/tests/SiteTest.php b/tests/SiteTest.php index 7db70ab5a..405f05511 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -602,7 +602,7 @@ public function test_isolation_will_persist_when_adding_ssl_certificate() // If site has an isolated PHP version for the site, it would replace .sock file $siteMock->shouldReceive('customPhpVersion')->with('site1.test')->andReturn('73')->once(); - $siteMock->shouldReceive('replaceSockFile')->withArgs([Mockery::any(), 'valet73.sock', '73'])->once(); + $siteMock->shouldReceive('replaceSockFile')->withArgs([Mockery::any(), '73'])->once(); resolve(Site::class)->secure('site1.test'); // For sites without an isolated PHP version, nothing should be replaced @@ -757,28 +757,28 @@ public function test_replace_sock_file_in_nginx_config() // When switching to php71, valet71.sock should be replaced with valet.sock; // isolation header should be prepended $this->assertEquals( - '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet.sock }', - $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', 'valet.sock', '71') + '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', + $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', '71') ); // When switching to php72, valet.sock should be replaced with valet72.sock $this->assertEquals( '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', - $site->replaceSockFile('server { fastcgi_pass: valet.sock }', 'valet72.sock', '72') + $site->replaceSockFile('server { fastcgi_pass: valet.sock }', '72') ); // When switching to php73 from php72, valet72.sock should be replaced with valet73.sock; // isolation header should be updated to php@7.3 $this->assertEquals( '# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', - $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', 'valet73.sock', '73') + $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', '73') ); // When switching to php72 from php74, valet72.sock should be replaced with valet74.sock; // isolation header should be updated to php@7.4 $this->assertEquals( '# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', - $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'valet74.sock', 'php@7.4') + $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'php@7.4') ); } } From 89fd8bc30b9f62b9a1a7848a81d322f5cbb45be0 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sun, 13 Mar 2022 04:29:11 +0000 Subject: [PATCH 21/41] Apply fixes from StyleCI --- cli/Valet/PhpFpm.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index b1910508a..3e7413049 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -76,7 +76,7 @@ public function uninstall() * * Writes FPM config file, pointing to the correct .sock file, and log and ini files. * - * @param string $phpVersion + * @param string $phpVersion * @return void */ public function createConfigurationFiles($phpVersion) @@ -298,7 +298,7 @@ public function useVersion($version, $force = false) * * @todo write tests * - * @param string $phpVersion + * @param string $phpVersion * @return void */ public function symlinkPrimaryValetSock($phpVersion) From 7226da5bb7bbee67b8b6297c687bc1d382b30ca3 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sun, 13 Mar 2022 22:17:11 -0400 Subject: [PATCH 22/41] Update valet.sock symlink --- cli/Valet/PhpFpm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index b1910508a..f8b487e6f 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -303,7 +303,7 @@ public function useVersion($version, $force = false) */ public function symlinkPrimaryValetSock($phpVersion) { - $this->files->symlink($this->fpmSockName($phpVersion), VALET_HOME_PATH.'/valet.sock'); + $this->files->symlinkAsUser(VALET_HOME_PATH . '/' . $this->fpmSockName($phpVersion), VALET_HOME_PATH.'/valet.sock'); } /** From 530e4c30dd7a42cb9d7cf91e3277e46f49641761 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sun, 13 Mar 2022 22:17:50 -0400 Subject: [PATCH 23/41] Update normalizePhpVersion regex Handle "php@8.1" Simplify the entire method into one block Co-Authored-By: Nathan Morgan --- cli/Valet/PhpFpm.php | 6 +----- tests/PhpFpmTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index f8b487e6f..59554ffc7 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -311,11 +311,7 @@ public function symlinkPrimaryValetSock($phpVersion) */ public function normalizePhpVersion($version) { - if (strpos($version, 'php') === false) { - $version = 'php'.$version; - } - - return preg_replace('/(php)([0-9+])(?:.)?([0-9+])/i', '$1@$2.$3', $version); + return preg_replace('/(?:php@?)?([0-9+])(?:.)?([0-9+])/i', 'php@$1.$2', $version); } /** diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index ecfa5c136..9d810afc6 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -51,6 +51,15 @@ public function test_it_can_generate_sock_file_name_from_php_version() $this->assertEquals('valet72.sock', resolve(PhpFpm::class)->fpmSockName('72')); } + public function test_it_normalizes_php_versions() + { + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('php@8.1')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('php8.1')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('php81')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('8.1')); + $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('81')); + } + public function test_utilized_php_versions() { $fileSystemMock = Mockery::mock(Filesystem::class); From 34f776bd0ae3e82d3ac504d013663b67f2652bf0 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sun, 13 Mar 2022 22:18:08 -0400 Subject: [PATCH 24/41] Re-work isolate and unisolate to run in cwd --- cli/valet.php | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/cli/valet.php b/cli/valet.php index 7679fa372..507e7b553 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -491,9 +491,9 @@ ]); /** - * Allow the user to change the version of php valet uses. + * Allow the user to change the version of php Valet uses. */ - $app->command('use [phpVersion] [--force] [--site=]', function ($phpVersion, $force, $site) { + $app->command('use [phpVersion] [--force]', function ($phpVersion, $force) { if (! $phpVersion) { $path = getcwd().'/.valetphprc'; $linkedVersion = Brew::linkedPhp(); @@ -509,30 +509,26 @@ } } - PhpFpm::useVersion($phpVersion, $force, $site); - })->descriptions('Change the version of PHP used by valet', [ + PhpFpm::useVersion($phpVersion, $force); + })->descriptions('Change the version of PHP used by Valet', [ 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', - '--site' => 'Isolate PHP version of a specific valet site. e.g: --site=site.test', ]); /** - * Allow the user to change the version of php valet uses to serve a given site. + * Allow the user to change the version of PHP Valet uses to serve the current site. */ - $app->command('isolate [site] [phpVersion] ', function ($site, $phpVersion) { - PhpFpm::isolateDirectory($site, $phpVersion); - })->descriptions('Change the version of PHP used by valet to serve a given site', [ - 'site' => 'The valet site (e.g. site.test) you want to isolate to a given PHP version', + $app->command('isolate [phpVersion] ', function ($phpVersion) { + PhpFpm::isolateDirectory(basename(getcwd()), $phpVersion); + })->descriptions('Change the version of PHP used by Valet to serve the current working directory', [ 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', ]); /** - * Allow the user to un-do specifying the version of php valet uses to serve a given site. + * Allow the user to un-do specifying the version of PHP Valet uses to serve the current site. */ - $app->command('unisolate [site] ', function ($site) { - PhpFpm::unIsolateDirectory($site); - })->descriptions('Stop customizing the version of PHP used by valet to serve a given site', [ - 'site' => 'The valet site (e.g. site.test) you want to un-isolate', - ]); + $app->command('unisolate', function () { + PhpFpm::unIsolateDirectory(basename(getcwd())); + })->descriptions('Stop customizing the version of PHP used by valet to serve the current working directory'); /** * Tail log file. From fd47384768f639d09ffe6321bc266f6c8046dd01 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 14 Mar 2022 02:18:58 +0000 Subject: [PATCH 25/41] Apply fixes from StyleCI --- cli/Valet/PhpFpm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 65674a712..9abd33790 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -303,7 +303,7 @@ public function useVersion($version, $force = false) */ public function symlinkPrimaryValetSock($phpVersion) { - $this->files->symlinkAsUser(VALET_HOME_PATH . '/' . $this->fpmSockName($phpVersion), VALET_HOME_PATH.'/valet.sock'); + $this->files->symlinkAsUser(VALET_HOME_PATH.'/'.$this->fpmSockName($phpVersion), VALET_HOME_PATH.'/valet.sock'); } /** From 148eb0174d945c73f275c3251c28421f0cd86f3b Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Sun, 13 Mar 2022 22:29:09 -0400 Subject: [PATCH 26/41] Drop test coverage for deprecated method --- tests/PhpFpmTest.php | 81 -------------------------------------------- 1 file changed, 81 deletions(-) diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 9d810afc6..fa7caf300 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -114,83 +114,6 @@ public function test_utilized_php_versions() $this->assertEquals(['php@7.1', 'php@7.2', 'php@7.3'], resolve(PhpFpm::class)->utilizedPhpVersions()); } - public function test_global_php_version_update_will_swap_socks() - { - $this->markTestIncomplete('Needs deleting or refactoring'); - - $fileSystemMock = Mockery::mock(Filesystem::class); - - $phpFpmMock = Mockery::mock(PhpFpm::class, [ - Mockery::mock(Brew::class), - Mockery::mock(CommandLine::class), - $fileSystemMock, - resolve(Configuration::class), - Mockery::mock(Site::class), - Mockery::mock(Nginx::class), - ])->makePartial(); - - swap(PhpFpm::class, $phpFpmMock); - - $fileSystemMock->shouldReceive('scandir') - ->once() - ->with(VALET_HOME_PATH.'/Nginx') - ->andReturn([ - '.gitkeep', - 'isolated-site-71.test', - 'isolated-site-72.test', - 'isolated-site-73.test', - 'non-isolated-site.test', - ]); - - // Skip dotfiles - $fileSystemMock->shouldNotReceive('get')->with(VALET_HOME_PATH.'/Nginx/.gitkeep'); - - // Any isolated site running on php72 would be replaced with default valet.sock, - // as 72 will be the default version after the global PHP version switch - $fileSystemMock->shouldReceive('get') - ->once() - ->with(VALET_HOME_PATH.'/Nginx/isolated-site-72.test') - ->andReturn('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }'); - - $fileSystemMock->shouldReceive('put')->once()->withArgs([ - VALET_HOME_PATH.'/Nginx/isolated-site-72.test', - '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', - ]); - - // Any isolated site running on current PHP version (with valet.sock), - // should be still be running on the same version after the global version update - $fileSystemMock->shouldReceive('get') - ->once() - ->with(VALET_HOME_PATH.'/Nginx/isolated-site-71.test') - ->andReturn('# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet.sock }'); - - $fileSystemMock->shouldReceive('put')->once()->withArgs([ - VALET_HOME_PATH.'/Nginx/isolated-site-71.test', - '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', - ]); - - // PHP 7.3 sites won't be affected here - $fileSystemMock->shouldReceive('get') - ->once() - ->with(VALET_HOME_PATH.'/Nginx/isolated-site-73.test') - ->andReturn('# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }'); - - $fileSystemMock->shouldNotReceive('put')->withArgs([ - VALET_HOME_PATH.'/Nginx/isolated-site-73.test', - Mockery::any(), - ]); - - // Nginx config that doesn't have the isolation header, It would not swap .sock files - $fileSystemMock->shouldReceive('get')->once()->with(VALET_HOME_PATH.'/Nginx/non-isolated-site.test')->andReturn('valet.sock'); - $fileSystemMock->shouldNotReceive('put')->withArgs([ - VALET_HOME_PATH.'/Nginx/non-isolated-site.test', - 'valet71.sock', - ]); - - // Switching from php7.1 to php7.2 - resolve(PhpFpm::class)->updateConfigurationForGlobalUpdate('php@7.2', 'php@7.1'); - } - public function test_stop_unused_php_versions() { $brewMock = Mockery::mock(Brew::class); @@ -323,9 +246,6 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $cliMock->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet.sock')->once(); $fileSystemMock->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock')->once(); - // $phpFpmMock->shouldReceive('createConfigurationFiles')->with('php@7.1')->once(); - // $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate')->withArgs(['php@7.2', 'php@7.1'])->once(); - $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', 'php@7.1', @@ -389,7 +309,6 @@ public function test_isolate_will_isolate_a_site() $brewMock->shouldNotReceive('unlink'); $phpFpmMock->shouldNotReceive('stopRunning'); $phpFpmMock->shouldNotReceive('install'); - // $phpFpmMock->shouldNotReceive('updateConfigurationForGlobalUpdate'); $this->assertSame(null, $phpFpmMock->isolateDirectory('test', 'php@7.2')); } From 95aa03977c03bbabf21b86fedcada82914970372 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 00:16:36 -0400 Subject: [PATCH 27/41] Add command to list isolated sites --- cli/Valet/Nginx.php | 13 +++++++++++++ cli/Valet/PhpFpm.php | 22 +++++++++++++++++----- cli/valet.php | 11 ++++++++++- tests/NginxTest.php | 22 ++++++++++++++++++++++ tests/PhpFpmTest.php | 15 +++++++++------ 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/cli/Valet/Nginx.php b/cli/Valet/Nginx.php index 0ab30d4cd..f27dfddd3 100644 --- a/cli/Valet/Nginx.php +++ b/cli/Valet/Nginx.php @@ -177,4 +177,17 @@ public function uninstall() $this->brew->uninstallFormula('nginx nginx-full'); $this->cli->quietly('rm -rf '.BREW_PREFIX.'/etc/nginx '.BREW_PREFIX.'/var/log/nginx'); } + + /** + * Return a list of all sites with explicit Nginx configurations + * + * @return \Illuminate\Support\Collection + */ + public function configuredSites() + { + return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) + ->reject(function ($file) { + return starts_with($file, '.'); + }); + } } diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 9abd33790..3acd13e6f 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -243,6 +243,22 @@ public function unIsolateDirectory($directory) info(sprintf('The site [%s] is now using the default PHP version.', $site)); } + /** + * List all directories with PHP isolation configured. + * + * @return \Illuminate\Support\Collection + */ + public function isolatedDirectories() + { + $configuredSites = $this->nginx->configuredSites(); + + return $configuredSites->filter(function ($item) { + return str_contains($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), 'Valet isolated PHP version'); + })->map(function ($item) { + return ['url' => $item]; + }); + } + /** * Use a specific version of PHP globally. * @@ -366,11 +382,7 @@ public function utilizedPhpVersions() return self::fpmSockName($this->normalizePhpVersion($version)); })->unique(); - return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) - ->reject(function ($file) { - return starts_with($file, '.'); - }) - ->map(function ($file) use ($fpmSockFiles) { + return $this->nginx->configuredSites()->map(function ($file) use ($fpmSockFiles) { $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); // Get the normalized PHP version for this config file, if it's defined diff --git a/cli/valet.php b/cli/valet.php index 507e7b553..663060bdd 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -528,7 +528,16 @@ */ $app->command('unisolate', function () { PhpFpm::unIsolateDirectory(basename(getcwd())); - })->descriptions('Stop customizing the version of PHP used by valet to serve the current working directory'); + })->descriptions('Stop customizing the version of PHP used by Valet to serve the current working directory'); + + /** + * List isolated sites + */ + $app->command('isolated', function () { + $sites = PhpFpm::isolatedDirectories(); + + table(['Path'], $sites->all()); + })->descriptions('List all sites using isolated versions of PHP.'); /** * Tail log file. diff --git a/tests/NginxTest.php b/tests/NginxTest.php index e2f780511..51f35a6d7 100644 --- a/tests/NginxTest.php +++ b/tests/NginxTest.php @@ -86,4 +86,26 @@ public function test_install_nginx_directories_rewrites_secure_nginx_files() $site->shouldHaveReceived('resecureForNewConfiguration', [$data, $data]); } + + public function test_it_gets_configured_sites() + { + $files = Mockery::mock(Filesystem::class); + + $files->shouldReceive('scandir') + ->once() + ->with(VALET_HOME_PATH . '/Nginx') + ->andReturn(['.gitkeep', 'isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test']); + + swap(Filesystem::class, $files); + swap(Configuration::class, $config = Mockery::spy(Configuration::class, ['read' => ['tld' => 'test', 'loopback' => VALET_LOOPBACK]])); + swap(Site::class, Mockery::mock(Site::class)); + + $nginx = resolve(Nginx::class); + $output = $nginx->configuredSites(); + + $this->assertEquals( + ['isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test'], + $output->values()->all() + ); + } } diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index fa7caf300..9247e6419 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -64,6 +64,7 @@ public function test_utilized_php_versions() { $fileSystemMock = Mockery::mock(Filesystem::class); $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, @@ -71,7 +72,7 @@ public function test_utilized_php_versions() $fileSystemMock, resolve(Configuration::class), Mockery::mock(Site::class), - Mockery::mock(Nginx::class), + $nginxMock, ])->makePartial(); swap(PhpFpm::class, $phpFpmMock); @@ -85,12 +86,9 @@ public function test_utilized_php_versions() $brewMock->shouldReceive('getLinkedPhpFormula')->andReturn('php@7.3'); - $fileSystemMock->shouldReceive('scandir') + $nginxMock->shouldReceive('configuredSites') ->once() - ->with(VALET_HOME_PATH.'/Nginx') - ->andReturn(['.gitkeep', 'isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test']); - - $fileSystemMock->shouldNotReceive('get')->with(VALET_HOME_PATH.'/Nginx/.gitkeep'); + ->andReturn(collect(['isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test'])); $sites = [ [ @@ -114,6 +112,11 @@ public function test_utilized_php_versions() $this->assertEquals(['php@7.1', 'php@7.2', 'php@7.3'], resolve(PhpFpm::class)->utilizedPhpVersions()); } + public function test_it_lists_isolated_directories() + { + $this->markTestIncomplete('@todo'); + } + public function test_stop_unused_php_versions() { $brewMock = Mockery::mock(Brew::class); From 9b8c41e3d3b3eb42f44d748b85acfd6fcf5e4ad8 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 14 Mar 2022 04:16:45 +0000 Subject: [PATCH 28/41] Apply fixes from StyleCI --- cli/Valet/Nginx.php | 4 ++-- cli/Valet/PhpFpm.php | 20 ++++++++++---------- cli/valet.php | 2 +- tests/NginxTest.php | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cli/Valet/Nginx.php b/cli/Valet/Nginx.php index f27dfddd3..ea4f8b127 100644 --- a/cli/Valet/Nginx.php +++ b/cli/Valet/Nginx.php @@ -179,13 +179,13 @@ public function uninstall() } /** - * Return a list of all sites with explicit Nginx configurations + * Return a list of all sites with explicit Nginx configurations. * * @return \Illuminate\Support\Collection */ public function configuredSites() { - return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) + return collect($this->files->scandir(VALET_HOME_PATH.'/Nginx')) ->reject(function ($file) { return starts_with($file, '.'); }); diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 3acd13e6f..0042743f5 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -383,18 +383,18 @@ public function utilizedPhpVersions() })->unique(); return $this->nginx->configuredSites()->map(function ($file) use ($fpmSockFiles) { - $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); + $content = $this->files->get(VALET_HOME_PATH.'/Nginx/'.$file); - // Get the normalized PHP version for this config file, if it's defined - foreach ($fpmSockFiles as $sock) { - if (strpos($content, $sock) !== false) { - // Extract the PHP version number from a custom .sock path; - // for example, "valet74.sock" will output "php74" - $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); + // Get the normalized PHP version for this config file, if it's defined + foreach ($fpmSockFiles as $sock) { + if (strpos($content, $sock) !== false) { + // Extract the PHP version number from a custom .sock path; + // for example, "valet74.sock" will output "php74" + $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); - return $this->normalizePhpVersion($phpVersion); // Example output php@7.4 - } + return $this->normalizePhpVersion($phpVersion); // Example output php@7.4 } - })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->values()->toArray(); + } + })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->values()->toArray(); } } diff --git a/cli/valet.php b/cli/valet.php index 663060bdd..1d9d72314 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -531,7 +531,7 @@ })->descriptions('Stop customizing the version of PHP used by Valet to serve the current working directory'); /** - * List isolated sites + * List isolated sites. */ $app->command('isolated', function () { $sites = PhpFpm::isolatedDirectories(); diff --git a/tests/NginxTest.php b/tests/NginxTest.php index 51f35a6d7..f05c39580 100644 --- a/tests/NginxTest.php +++ b/tests/NginxTest.php @@ -93,7 +93,7 @@ public function test_it_gets_configured_sites() $files->shouldReceive('scandir') ->once() - ->with(VALET_HOME_PATH . '/Nginx') + ->with(VALET_HOME_PATH.'/Nginx') ->andReturn(['.gitkeep', 'isolated-site-71.test', 'isolated-site-72.test', 'isolated-site-73.test']); swap(Filesystem::class, $files); From 8f7ea041b69d8160ad7873171f41c2208b27af08 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 12:41:04 -0400 Subject: [PATCH 29/41] Test isolatedDirectories --- tests/PhpFpmTest.php | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 9247e6419..48e1dd06e 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -114,7 +114,44 @@ public function test_utilized_php_versions() public function test_it_lists_isolated_directories() { - $this->markTestIncomplete('@todo'); + $fileSystemMock = Mockery::mock(Filesystem::class); + $nginxMock = Mockery::mock(Nginx::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + Mockery::mock(Brew::class), + Mockery::mock(CommandLine::class), + $fileSystemMock, + resolve(Configuration::class), + Mockery::mock(Site::class), + $nginxMock, + ])->makePartial(); + + swap(PhpFpm::class, $phpFpmMock); + + $nginxMock->shouldReceive('configuredSites') + ->once() + ->andReturn(collect(['isolated-site-71.test', 'isolated-site-72.test', 'not-isolated-site.test'])); + + $sites = [ + [ + 'site' => 'isolated-site-71.test', + 'conf' => '# Valet isolated PHP version : 71' . PHP_EOL . 'valet71.sock', + ], + [ + 'site' => 'isolated-site-72.test', + 'conf' => '# Valet isolated PHP version : php@7.2' . PHP_EOL . 'valet72.sock', + ], + [ + 'site' => 'not-isolated-site.test', + 'conf' => 'This one is not isolated', + ], + ]; + + foreach ($sites as $site) { + $fileSystemMock->shouldReceive('get')->once()->with(VALET_HOME_PATH.'/Nginx/'.$site['site'])->andReturn($site['conf']); + } + + $this->assertEquals(['isolated-site-71.test', 'isolated-site-72.test'], resolve(PhpFpm::class)->isolatedDirectories()->pluck('url')->toArray()); } public function test_stop_unused_php_versions() @@ -316,7 +353,7 @@ public function test_isolate_will_isolate_a_site() $this->assertSame(null, $phpFpmMock->isolateDirectory('test', 'php@7.2')); } - public function test_un_isolate_can_remove_isolation_for_a_site() + public function test_un_isolate_will_remove_isolation_for_a_site() { $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); From 38a19291ce9efd5f7a68f9ac0efb9d6646414ea4 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 14 Mar 2022 16:41:13 +0000 Subject: [PATCH 30/41] Apply fixes from StyleCI --- tests/PhpFpmTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 48e1dd06e..53ab19b95 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -135,11 +135,11 @@ public function test_it_lists_isolated_directories() $sites = [ [ 'site' => 'isolated-site-71.test', - 'conf' => '# Valet isolated PHP version : 71' . PHP_EOL . 'valet71.sock', + 'conf' => '# Valet isolated PHP version : 71'.PHP_EOL.'valet71.sock', ], [ 'site' => 'isolated-site-72.test', - 'conf' => '# Valet isolated PHP version : php@7.2' . PHP_EOL . 'valet72.sock', + 'conf' => '# Valet isolated PHP version : php@7.2'.PHP_EOL.'valet72.sock', ], [ 'site' => 'not-isolated-site.test', From 3cdb7c78f4cc57bdfa24366be12d6bcff6ffa2d7 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 12:42:11 -0400 Subject: [PATCH 31/41] Drop space before colon in magic isolation string --- cli/Valet/Site.php | 2 +- cli/stubs/site.valet.conf | 2 +- tests/PhpFpmTest.php | 10 +++++----- tests/SiteTest.php | 20 ++++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 71519924d..4d124c957 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -1104,6 +1104,6 @@ public function replaceSockFile($siteConf, $phpVersion) $siteConf = preg_replace('/valet[0-9]*.sock/', $sockFile, $siteConf); $siteConf = preg_replace('/# Valet isolated PHP version.*\n/', '', $siteConf); // Remove `Valet isolated PHP version` line from config - return '# Valet isolated PHP version : '.$phpVersion.PHP_EOL.$siteConf; + return '# Valet isolated PHP version: '.$phpVersion.PHP_EOL.$siteConf; } } diff --git a/cli/stubs/site.valet.conf b/cli/stubs/site.valet.conf index 26109aef4..26f531141 100644 --- a/cli/stubs/site.valet.conf +++ b/cli/stubs/site.valet.conf @@ -1,4 +1,4 @@ -# Valet isolated PHP version : VALET_ISOLATED_PHP_VERSION +# Valet isolated PHP version: VALET_ISOLATED_PHP_VERSION server { listen 127.0.0.1:80; server_name VALET_SITE www.VALET_SITE *.VALET_SITE; diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 48e1dd06e..c038e6d2d 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -93,15 +93,15 @@ public function test_utilized_php_versions() $sites = [ [ 'site' => 'isolated-site-71.test', - 'conf' => '# Valet isolated PHP version : 71'.PHP_EOL.'valet71.sock', + 'conf' => '# Valet isolated PHP version: 71'.PHP_EOL.'valet71.sock', ], [ 'site' => 'isolated-site-72.test', - 'conf' => '# Valet isolated PHP version : php@7.2'.PHP_EOL.'valet72.sock', + 'conf' => '# Valet isolated PHP version: php@7.2'.PHP_EOL.'valet72.sock', ], [ 'site' => 'isolated-site-73.test', - 'conf' => '# Valet isolated PHP version : 73'.PHP_EOL.'valet.sock', + 'conf' => '# Valet isolated PHP version: 73'.PHP_EOL.'valet.sock', ], ]; @@ -135,11 +135,11 @@ public function test_it_lists_isolated_directories() $sites = [ [ 'site' => 'isolated-site-71.test', - 'conf' => '# Valet isolated PHP version : 71' . PHP_EOL . 'valet71.sock', + 'conf' => '# Valet isolated PHP version: 71' . PHP_EOL . 'valet71.sock', ], [ 'site' => 'isolated-site-72.test', - 'conf' => '# Valet isolated PHP version : php@7.2' . PHP_EOL . 'valet72.sock', + 'conf' => '# Valet isolated PHP version: php@7.2' . PHP_EOL . 'valet72.sock', ], [ 'site' => 'not-isolated-site.test', diff --git a/tests/SiteTest.php b/tests/SiteTest.php index b583736ca..840ca94f9 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -659,13 +659,13 @@ public function test_can_install_nginx_site_config_for_specific_php_version() $files->shouldReceive('get') ->once() ->with($siteMock->nginxPath('site1.test')) - ->andReturn('# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }'); + ->andReturn('# Valet isolated PHP version: php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }'); $files->shouldReceive('putAsUser') ->once() ->withArgs([ $siteMock->nginxPath('site1.test'), - '# Valet isolated PHP version : php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', + '# Valet isolated PHP version: php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', ]); $siteMock->isolate('site1.test', 'php@8.0'); @@ -682,7 +682,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() ->withArgs([ $siteMock->nginxPath('site2.test'), Mockery::on(function ($argument) { - return preg_match('/^# Valet isolated PHP version : php@8.0/', $argument) + return preg_match('/^# Valet isolated PHP version: php@8.0/', $argument) && preg_match('#fastcgi_pass "unix:.*/valet80.sock#', $argument) && strpos($argument, 'server_name site2.test www.site2.test *.site2.test;') !== false; }), @@ -733,7 +733,7 @@ public function test_retrieves_custom_php_version_from_nginx_config() $files->shouldReceive('get') ->once() ->with($siteMock->nginxPath('site1.test')) - ->andReturn('# Valet isolated PHP version : php@7.4'); + ->andReturn('# Valet isolated PHP version: php@7.4'); $this->assertEquals('74', resolve(Site::class)->customPhpVersion('site1.test')); // Site without any custom nginx config @@ -757,28 +757,28 @@ public function test_replace_sock_file_in_nginx_config() // When switching to php71, valet71.sock should be replaced with valet.sock; // isolation header should be prepended $this->assertEquals( - '# Valet isolated PHP version : 71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', + '# Valet isolated PHP version: 71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', '71') ); // When switching to php72, valet.sock should be replaced with valet72.sock $this->assertEquals( - '# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', + '# Valet isolated PHP version: 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', $site->replaceSockFile('server { fastcgi_pass: valet.sock }', '72') ); // When switching to php73 from php72, valet72.sock should be replaced with valet73.sock; // isolation header should be updated to php@7.3 $this->assertEquals( - '# Valet isolated PHP version : 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', - $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', '73') + '# Valet isolated PHP version: 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', + $site->replaceSockFile('# Valet isolated PHP version: 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', '73') ); // When switching to php72 from php74, valet72.sock should be replaced with valet74.sock; // isolation header should be updated to php@7.4 $this->assertEquals( - '# Valet isolated PHP version : php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', - $site->replaceSockFile('# Valet isolated PHP version : 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'php@7.4') + '# Valet isolated PHP version: php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', + $site->replaceSockFile('# Valet isolated PHP version: 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'php@7.4') ); } From 118e0a36921dffc2d660905deabd1beabb6d4dfe Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 12:55:20 -0400 Subject: [PATCH 32/41] Update str_contains to strpos --- cli/Valet/PhpFpm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 0042743f5..278f4b11b 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -253,7 +253,7 @@ public function isolatedDirectories() $configuredSites = $this->nginx->configuredSites(); return $configuredSites->filter(function ($item) { - return str_contains($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), 'Valet isolated PHP version'); + return strpos($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), 'Valet isolated PHP version') !== false; })->map(function ($item) { return ['url' => $item]; }); From 984d7eb6991634e1e3fb145a407026d7f0fec640 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 13:41:48 -0400 Subject: [PATCH 33/41] Add PHP Version to the isolated command --- cli/Valet/PhpFpm.php | 2 +- cli/valet.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 278f4b11b..1096a2dca 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -255,7 +255,7 @@ public function isolatedDirectories() return $configuredSites->filter(function ($item) { return strpos($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), 'Valet isolated PHP version') !== false; })->map(function ($item) { - return ['url' => $item]; + return ['url' => $item, 'version' => $this->normalizePhpVersion($this->site->customPhpVersion($item))]; }); } diff --git a/cli/valet.php b/cli/valet.php index b20fe5a6b..e009188e3 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -547,7 +547,7 @@ $app->command('isolated', function () { $sites = PhpFpm::isolatedDirectories(); - table(['Path'], $sites->all()); + table(['Path', 'PHP Version'], $sites->all()); })->descriptions('List all sites using isolated versions of PHP.'); /** From ce4682f897c8494afabfdd043ad2082bd10243df Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 13:57:45 -0400 Subject: [PATCH 34/41] Fix PHPFpm tests - Fix the isolated directories test given new table shape - Updated useVersion test to no longer hit the real filesystem Co-Authored-By: Jacob Baker-Kretzmar <18192441+bakerkretzmar@users.noreply.github.com> --- tests/PhpFpmTest.php | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index e72f604d5..afffde190 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -116,13 +116,14 @@ public function test_it_lists_isolated_directories() { $fileSystemMock = Mockery::mock(Filesystem::class); $nginxMock = Mockery::mock(Nginx::class); + $site = Mockery::mock(Site::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ Mockery::mock(Brew::class), Mockery::mock(CommandLine::class), $fileSystemMock, resolve(Configuration::class), - Mockery::mock(Site::class), + $site, $nginxMock, ])->makePartial(); @@ -132,6 +133,11 @@ public function test_it_lists_isolated_directories() ->once() ->andReturn(collect(['isolated-site-71.test', 'isolated-site-72.test', 'not-isolated-site.test'])); + $site->shouldReceive('customPhpVersion')->with('isolated-site-71.test')->andReturn('71'); + $site->shouldReceive('customPhpVersion')->with('isolated-site-72.test')->andReturn('72'); + $site->shouldReceive('normalizePhpVersion')->with('71')->andReturn('php@7.1'); + $site->shouldReceive('normalizePhpVersion')->with('72')->andReturn('php@7.2'); + $sites = [ [ 'site' => 'isolated-site-71.test', @@ -151,7 +157,16 @@ public function test_it_lists_isolated_directories() $fileSystemMock->shouldReceive('get')->once()->with(VALET_HOME_PATH.'/Nginx/'.$site['site'])->andReturn($site['conf']); } - $this->assertEquals(['isolated-site-71.test', 'isolated-site-72.test'], resolve(PhpFpm::class)->isolatedDirectories()->pluck('url')->toArray()); + $this->assertEquals([ + [ + 'url' => 'isolated-site-71.test', + 'version' => 'php@7.1', + ], + [ + 'url' => 'isolated-site-72.test', + 'version' => 'php@7.2', + ] + ], resolve(PhpFpm::class)->isolatedDirectories()->toArray()); } public function test_stop_unused_php_versions() @@ -215,14 +230,17 @@ public function test_stopRunning_will_pass_filtered_result_of_getRunningServices public function test_use_version_will_convert_passed_php_version() { + // @todo mock CLI and filesystem so real valet.sock files aren't deleted $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); + $filesystem = Mockery::mock(Filesystem::class); + $cli = Mockery::mock(CommandLine::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, - resolve(CommandLine::class), - resolve(Filesystem::class), + $cli, + $filesystem, resolve(Configuration::class), $siteMock, $nginxMock, @@ -245,6 +263,10 @@ public function test_use_version_will_convert_passed_php_version() $nginxMock->shouldReceive('restart'); + $filesystem->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock'); + + $cli->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet.sock'); + // Test both non prefixed and prefixed $this->assertSame('php@7.2', $phpFpmMock->useVersion('php7.2')); $this->assertSame('php@7.2', $phpFpmMock->useVersion('php72')); From 791a047576d56bec50b1680256f470a3f8d56bb3 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 14 Mar 2022 17:57:55 +0000 Subject: [PATCH 35/41] Apply fixes from StyleCI --- tests/PhpFpmTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index afffde190..db6f88f05 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -165,7 +165,7 @@ public function test_it_lists_isolated_directories() [ 'url' => 'isolated-site-72.test', 'version' => 'php@7.2', - ] + ], ], resolve(PhpFpm::class)->isolatedDirectories()->toArray()); } From 17cda5dc797c5887ebf96ef0a240602e136851f1 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 13:58:52 -0400 Subject: [PATCH 36/41] Drop todos --- cli/Valet/PhpFpm.php | 2 -- tests/PhpFpmTest.php | 1 - 2 files changed, 3 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 1096a2dca..8e31284e3 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -312,8 +312,6 @@ public function useVersion($version, $force = false) /** * Symlink (Capistrano-style) a given Valet.sock file to be the primary valet.sock. * - * @todo write tests - * * @param string $phpVersion * @return void */ diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index afffde190..a4ca14cc1 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -230,7 +230,6 @@ public function test_stopRunning_will_pass_filtered_result_of_getRunningServices public function test_use_version_will_convert_passed_php_version() { - // @todo mock CLI and filesystem so real valet.sock files aren't deleted $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); From b8885a4115a19fffbf54c4f9e0c115a3589f4cb1 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 14:10:49 -0400 Subject: [PATCH 37/41] Move deleting valet.sock into install() Co-Authored-By: Jacob Baker-Kretzmar <18192441+bakerkretzmar@users.noreply.github.com> --- cli/Valet/PhpFpm.php | 9 +++++---- tests/PhpFpmTest.php | 13 +++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 8e31284e3..1d7f09c58 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -54,6 +54,11 @@ public function install() $phpVersion = $this->brew->linkedPhp(); $this->createConfigurationFiles($phpVersion); + + // Remove old valet.sock + $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet.sock'); + $this->symlinkPrimaryValetSock($phpVersion); $this->restart(); @@ -293,10 +298,6 @@ public function useVersion($version, $force = false) $this->stopRunning(); - // Remove valet.sock - $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet.sock'); - $this->install(); $newVersion = $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 4d093d97b..3a528227b 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -60,6 +60,11 @@ public function test_it_normalizes_php_versions() $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('81')); } + public function test_it_installs() + { + $this->markTestIncomplete('todo'); + } + public function test_utilized_php_versions() { $fileSystemMock = Mockery::mock(Filesystem::class); @@ -291,21 +296,17 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $brewMock = Mockery::mock(Brew::class); $nginxMock = Mockery::mock(Nginx::class); $siteMock = Mockery::mock(Site::class); - $cliMock = Mockery::mock(CommandLine::class); - $fileSystemMock = Mockery::mock(Filesystem::class); $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, - $cliMock, - $fileSystemMock, + resolve(CommandLine::class), + resolve(Filesystem::class), resolve(Configuration::class), $siteMock, $nginxMock, ])->makePartial(); $phpFpmMock->shouldReceive('install'); - $cliMock->shouldReceive('quietly')->with('sudo rm '.VALET_HOME_PATH.'/valet.sock')->once(); - $fileSystemMock->shouldReceive('unlink')->with(VALET_HOME_PATH.'/valet.sock')->once(); $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ 'php@7.2', From e4c7a9b3e5f89d8819ee25240d9dd2f983e177c9 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 14:22:37 -0400 Subject: [PATCH 38/41] Symlink valet.sock *after* restarting so it's not deleted by restarting PHP-FPM Co-Authored-By: Jacob Baker-Kretzmar <18192441+bakerkretzmar@users.noreply.github.com> --- cli/Valet/PhpFpm.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 1d7f09c58..a1e209775 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -59,9 +59,9 @@ public function install() $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet.sock'); - $this->symlinkPrimaryValetSock($phpVersion); - $this->restart(); + + $this->symlinkPrimaryValetSock($phpVersion); } /** From 383aa621379b531a532cfc015c0985859be1659f Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 14:40:45 -0400 Subject: [PATCH 39/41] Change magic isolation config string to "ISOLATED_PHP_VERSION" Co-Authored-By: Jacob Baker-Kretzmar <18192441+bakerkretzmar@users.noreply.github.com> --- cli/Valet/PhpFpm.php | 2 +- cli/Valet/Site.php | 6 +++--- cli/includes/helpers.php | 2 ++ cli/stubs/site.valet.conf | 2 +- tests/PhpFpmTest.php | 10 +++++----- tests/SiteTest.php | 20 ++++++++++---------- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index a1e209775..42ac1b097 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -258,7 +258,7 @@ public function isolatedDirectories() $configuredSites = $this->nginx->configuredSites(); return $configuredSites->filter(function ($item) { - return strpos($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), 'Valet isolated PHP version') !== false; + return strpos($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), ISOLATED_PHP_VERSION) !== false; })->map(function ($item) { return ['url' => $item, 'version' => $this->normalizePhpVersion($this->site->customPhpVersion($item))]; }); diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 4d124c957..660f68bac 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -1082,7 +1082,7 @@ public function customPhpVersion($url) if ($this->files->exists($this->nginxPath($url))) { $siteConf = $this->files->get($this->nginxPath($url)); - if (starts_with($siteConf, '# Valet isolated PHP version')) { + if (starts_with($siteConf, '# '.ISOLATED_PHP_VERSION)) { $firstLine = explode(PHP_EOL, $siteConf)[0]; return preg_replace("/[^\d]*/", '', $firstLine); // Example output: "74" or "81" @@ -1102,8 +1102,8 @@ public function replaceSockFile($siteConf, $phpVersion) $sockFile = PhpFpm::fpmSockName($phpVersion); $siteConf = preg_replace('/valet[0-9]*.sock/', $sockFile, $siteConf); - $siteConf = preg_replace('/# Valet isolated PHP version.*\n/', '', $siteConf); // Remove `Valet isolated PHP version` line from config + $siteConf = preg_replace('/# '.ISOLATED_PHP_VERSION.'.*\n/', '', $siteConf); // Remove ISOLATED_PHP_VERSION line from config - return '# Valet isolated PHP version: '.$phpVersion.PHP_EOL.$siteConf; + return '# '.ISOLATED_PHP_VERSION.'='.$phpVersion.PHP_EOL.$siteConf; } } diff --git a/cli/includes/helpers.php b/cli/includes/helpers.php index 1daf74fec..352d867fb 100644 --- a/cli/includes/helpers.php +++ b/cli/includes/helpers.php @@ -23,6 +23,8 @@ define('BREW_PREFIX', (new CommandLine())->runAsUser('printf $(brew --prefix)')); +define('ISOLATED_PHP_VERSION', 'ISOLATED_PHP_VERSION'); + /** * Output the given text to the console. * diff --git a/cli/stubs/site.valet.conf b/cli/stubs/site.valet.conf index 26f531141..9fb0a7939 100644 --- a/cli/stubs/site.valet.conf +++ b/cli/stubs/site.valet.conf @@ -1,4 +1,4 @@ -# Valet isolated PHP version: VALET_ISOLATED_PHP_VERSION +# ISOLATED_PHP_VERSION=VALET_ISOLATED_PHP_VERSION server { listen 127.0.0.1:80; server_name VALET_SITE www.VALET_SITE *.VALET_SITE; diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 3a528227b..0632c6741 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -98,15 +98,15 @@ public function test_utilized_php_versions() $sites = [ [ 'site' => 'isolated-site-71.test', - 'conf' => '# Valet isolated PHP version: 71'.PHP_EOL.'valet71.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=71'.PHP_EOL.'valet71.sock', ], [ 'site' => 'isolated-site-72.test', - 'conf' => '# Valet isolated PHP version: php@7.2'.PHP_EOL.'valet72.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=php@7.2'.PHP_EOL.'valet72.sock', ], [ 'site' => 'isolated-site-73.test', - 'conf' => '# Valet isolated PHP version: 73'.PHP_EOL.'valet.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=73'.PHP_EOL.'valet.sock', ], ]; @@ -146,11 +146,11 @@ public function test_it_lists_isolated_directories() $sites = [ [ 'site' => 'isolated-site-71.test', - 'conf' => '# Valet isolated PHP version: 71'.PHP_EOL.'valet71.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=71'.PHP_EOL.'valet71.sock', ], [ 'site' => 'isolated-site-72.test', - 'conf' => '# Valet isolated PHP version: php@7.2'.PHP_EOL.'valet72.sock', + 'conf' => '# '.ISOLATED_PHP_VERSION.'=php@7.2'.PHP_EOL.'valet72.sock', ], [ 'site' => 'not-isolated-site.test', diff --git a/tests/SiteTest.php b/tests/SiteTest.php index 840ca94f9..e8e03d41e 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -659,13 +659,13 @@ public function test_can_install_nginx_site_config_for_specific_php_version() $files->shouldReceive('get') ->once() ->with($siteMock->nginxPath('site1.test')) - ->andReturn('# Valet isolated PHP version: php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }'); + ->andReturn('# '.ISOLATED_PHP_VERSION.'=php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }'); $files->shouldReceive('putAsUser') ->once() ->withArgs([ $siteMock->nginxPath('site1.test'), - '# Valet isolated PHP version: php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', + '# '.ISOLATED_PHP_VERSION.'=php@8.0'.PHP_EOL.'server { fastcgi_pass: valet80.sock }', ]); $siteMock->isolate('site1.test', 'php@8.0'); @@ -682,7 +682,7 @@ public function test_can_install_nginx_site_config_for_specific_php_version() ->withArgs([ $siteMock->nginxPath('site2.test'), Mockery::on(function ($argument) { - return preg_match('/^# Valet isolated PHP version: php@8.0/', $argument) + return preg_match('/^# '.ISOLATED_PHP_VERSION.'=php@8.0/', $argument) && preg_match('#fastcgi_pass "unix:.*/valet80.sock#', $argument) && strpos($argument, 'server_name site2.test www.site2.test *.site2.test;') !== false; }), @@ -733,7 +733,7 @@ public function test_retrieves_custom_php_version_from_nginx_config() $files->shouldReceive('get') ->once() ->with($siteMock->nginxPath('site1.test')) - ->andReturn('# Valet isolated PHP version: php@7.4'); + ->andReturn('# '.ISOLATED_PHP_VERSION.'=php@7.4'); $this->assertEquals('74', resolve(Site::class)->customPhpVersion('site1.test')); // Site without any custom nginx config @@ -757,28 +757,28 @@ public function test_replace_sock_file_in_nginx_config() // When switching to php71, valet71.sock should be replaced with valet.sock; // isolation header should be prepended $this->assertEquals( - '# Valet isolated PHP version: 71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', + '# '.ISOLATED_PHP_VERSION.'=71'.PHP_EOL.'server { fastcgi_pass: valet71.sock }', $site->replaceSockFile('server { fastcgi_pass: valet71.sock }', '71') ); // When switching to php72, valet.sock should be replaced with valet72.sock $this->assertEquals( - '# Valet isolated PHP version: 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', + '# '.ISOLATED_PHP_VERSION.'=72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', $site->replaceSockFile('server { fastcgi_pass: valet.sock }', '72') ); // When switching to php73 from php72, valet72.sock should be replaced with valet73.sock; // isolation header should be updated to php@7.3 $this->assertEquals( - '# Valet isolated PHP version: 73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', - $site->replaceSockFile('# Valet isolated PHP version: 72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', '73') + '# '.ISOLATED_PHP_VERSION.'=73'.PHP_EOL.'server { fastcgi_pass: valet73.sock }', + $site->replaceSockFile('# '.ISOLATED_PHP_VERSION.'=72'.PHP_EOL.'server { fastcgi_pass: valet72.sock }', '73') ); // When switching to php72 from php74, valet72.sock should be replaced with valet74.sock; // isolation header should be updated to php@7.4 $this->assertEquals( - '# Valet isolated PHP version: php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', - $site->replaceSockFile('# Valet isolated PHP version: 72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'php@7.4') + '# '.ISOLATED_PHP_VERSION.'=php@7.4'.PHP_EOL.'server { fastcgi_pass: valet74.sock }', + $site->replaceSockFile('# '.ISOLATED_PHP_VERSION.'=72'.PHP_EOL.'server { fastcgi_pass: valet.sock }', 'php@7.4') ); } From b1d9b2b6692169cbbd64f8a93259eaa70e1ce51b Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 15:00:05 -0400 Subject: [PATCH 40/41] Clean up --- cli/Valet/PhpFpm.php | 11 +++-------- tests/PhpFpmTest.php | 5 ----- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 42ac1b097..44dff63f4 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -255,9 +255,7 @@ public function unIsolateDirectory($directory) */ public function isolatedDirectories() { - $configuredSites = $this->nginx->configuredSites(); - - return $configuredSites->filter(function ($item) { + return $this->nginx->configuredSites()->filter(function ($item) { return strpos($this->files->get(VALET_HOME_PATH.'/Nginx/'.$item), ISOLATED_PHP_VERSION) !== false; })->map(function ($item) { return ['url' => $item, 'version' => $this->normalizePhpVersion($this->site->customPhpVersion($item))]; @@ -387,11 +385,8 @@ public function utilizedPhpVersions() // Get the normalized PHP version for this config file, if it's defined foreach ($fpmSockFiles as $sock) { if (strpos($content, $sock) !== false) { - // Extract the PHP version number from a custom .sock path; - // for example, "valet74.sock" will output "php74" - $phpVersion = 'php'.str_replace(['valet', '.sock'], '', $sock); - - return $this->normalizePhpVersion($phpVersion); // Example output php@7.4 + // Extract the PHP version number from a custom .sock path and normalize it to, e.g., "php@7.4" + return $this->normalizePhpVersion(str_replace(['valet', '.sock'], '', $sock)); } } })->merge([$this->brew->getLinkedPhpFormula()])->filter()->unique()->values()->toArray(); diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 0632c6741..68f807473 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -60,11 +60,6 @@ public function test_it_normalizes_php_versions() $this->assertEquals('php@8.1', resolve(PhpFpm::class)->normalizePhpVersion('81')); } - public function test_it_installs() - { - $this->markTestIncomplete('todo'); - } - public function test_utilized_php_versions() { $fileSystemMock = Mockery::mock(Filesystem::class); From b09a9163fad8039f06e47fc3a82ec27081f4e304 Mon Sep 17 00:00:00 2001 From: Matt Stauffer Date: Mon, 14 Mar 2022 15:02:16 -0400 Subject: [PATCH 41/41] Inline site check in unisolate command --- cli/Valet/PhpFpm.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 44dff63f4..b9403b293 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -233,9 +233,7 @@ public function isolateDirectory($directory, $version) */ public function unIsolateDirectory($directory) { - $site = $this->site->getSiteUrl($directory); - - if (! $site) { + if (! $site = $this->site->getSiteUrl($directory)) { throw new DomainException("The [{$directory}] site could not be found in Valet's site list."); }