diff --git a/cli/Valet/Brew.php b/cli/Valet/Brew.php index b4e247738..95334f12a 100644 --- a/cli/Valet/Brew.php +++ b/cli/Valet/Brew.php @@ -62,7 +62,7 @@ function hasInstalledPhp() } /** - * Get a list of supported PHP versions + * Get a list of supported PHP versions. * * @return \Illuminate\Support\Collection */ @@ -83,7 +83,7 @@ function hasInstalledNginx() } /** - * Return name of the nginx service installed via Homebrewed. + * Return name of the nginx service installed via Homebrew. * * @return string */ @@ -185,7 +185,7 @@ function stopService($services) } /** - * Determine if php is currently linked + * Determine if php is currently linked. * * @return bool */ @@ -195,7 +195,7 @@ function hasLinkedPhp() } /** - * Get the linked php parsed + * Get the linked php parsed. * * @return mixed */ @@ -277,7 +277,17 @@ function createSudoersEntry() } /** - * Link passed formula + * Remove the "sudoers.d" entry for running Brew. + * + * @return void + */ + function removeSudoersEntry() + { + $this->cli->quietly('rm /etc/sudoers.d/brew'); + } + + /** + * Link passed formula. * * @param $formula * @param bool $force @@ -297,7 +307,7 @@ function ($exitCode, $errorOutput) use ($formula) { } /** - * Unlink passed formula + * Unlink passed formula. * @param $formula * * @return string @@ -315,7 +325,7 @@ function ($exitCode, $errorOutput) use ($formula) { } /** - * Get the currently running brew services + * Get the currently running brew services. * * @return \Illuminate\Support\Collection */ @@ -330,4 +340,45 @@ function ($exitCode, $errorOutput) { } )))); } + + /** + * Tell Homebrew to forcefully remove all PHP versions that Valet supports. + * + * @return string + */ + function uninstallAllPhpVersions() + { + $this->supportedPhpVersions()->each(function ($formula) { + $this->uninstallFormula($formula); + }); + + return 'PHP versions removed.'; + } + + /** + * Uninstall a Homebrew app by formula name. + * @param string $formula + * + * @return void + */ + function uninstallFormula($formula) + { + $this->cli->runAsUser('brew uninstall --force '.$formula); + $this->cli->run('rm -rf /usr/local/Cellar/'.$formula); + } + + /** + * Run Homebrew's cleanup commands. + * + * @return string + */ + function cleanupBrew() + { + return $this->cli->runAsUser( + 'brew cleanup && brew services cleanup', + function ($exitCode, $errorOutput) { + output($errorOutput); + } + ); + } } diff --git a/cli/Valet/Configuration.php b/cli/Valet/Configuration.php index cf36e838b..d0095db45 100644 --- a/cli/Valet/Configuration.php +++ b/cli/Valet/Configuration.php @@ -34,6 +34,16 @@ function install() $this->files->chown($this->path(), user()); } + /** + * Forcefully delete the Valet home configuration directory and contents. + * + * @return void + */ + function uninstall() + { + $this->files->unlink(VALET_HOME_PATH); + } + /** * Create the Valet configuration directory. * diff --git a/cli/Valet/DnsMasq.php b/cli/Valet/DnsMasq.php index 1b49c53ce..506f2ad72 100644 --- a/cli/Valet/DnsMasq.php +++ b/cli/Valet/DnsMasq.php @@ -51,6 +51,23 @@ function install($tld = 'test') info('Valet is configured to serve for TLD [.'.$tld.']'); } + /** + * Forcefully uninstall dnsmasq. + * + * @return void + */ + function uninstall() + { + $this->brew->stopService('dnsmasq'); + $this->brew->uninstallFormula('dnsmasq'); + $this->cli->run('rm -rf /usr/local/etc/dnsmasq.d/dnsmasq-valet.conf'); + } + + /** + * Tell Homebrew to restart dnsmasq + * + * @return void + */ function restart() { $this->brew->restartService('dnsmasq'); diff --git a/cli/Valet/Nginx.php b/cli/Valet/Nginx.php index 7e9ea2251..7b369871e 100644 --- a/cli/Valet/Nginx.php +++ b/cli/Valet/Nginx.php @@ -160,12 +160,14 @@ function stop() } /** - * Prepare Nginx for uninstallation. + * Forcefully uninstall Nginx. * * @return void */ function uninstall() { - $this->stop(); + $this->brew->stopService(['nginx', 'nginx-full']); + $this->brew->uninstallFormula('nginx nginx-full'); + $this->cli->quietly('rm -rf /usr/local/etc/nginx /usr/local/var/log/nginx'); } } diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index cf6bff19c..d809ac067 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -45,6 +45,18 @@ function install() $this->restart(); } + /** + * Forcefully uninstall all of Valet's supported PHP versions and configurations + * + * @return void + */ + function uninstall() + { + $this->brew->uninstallAllPhpVersions(); + rename('/usr/local/etc/php', '/usr/local/etc/php-valet-bak'.time()); + $this->cli->run('rm -rf /usr/local/var/log/php-fpm.log'); + } + /** * Update the PHP FPM configuration. * diff --git a/cli/Valet/Valet.php b/cli/Valet/Valet.php index 1f9352fac..3fe00aa4b 100644 --- a/cli/Valet/Valet.php +++ b/cli/Valet/Valet.php @@ -34,6 +34,16 @@ function symlinkToUsersBin() $this->cli->runAsUser('ln -s "'.realpath(__DIR__.'/../../valet').'" '.$this->valetBin); } + /** + * Remove the symlink from the user's local bin. + * + * @return void + */ + function unlinkFromUsersBin() + { + $this->cli->quietlyAsUser('rm '.$this->valetBin); + } + /** * Get the paths to all of the Valet extensions. * @@ -81,4 +91,30 @@ function createSudoersEntry() $this->files->put('/etc/sudoers.d/valet', 'Cmnd_Alias VALET = /usr/local/bin/valet * %admin ALL=(root) NOPASSWD:SETENV: VALET'.PHP_EOL); } + + /** + * Remove the "sudoers.d" entry for running Valet. + * + * @return void + */ + function removeSudoersEntry() + { + $this->cli->quietly('rm /etc/sudoers.d/valet'); + } + + /** + * Run composer global diagnose + */ + function composerGlobalDiagnose() + { + $this->cli->runAsUser('composer global diagnose'); + } + + /** + * Run composer global update + */ + function composerGlobalUpdate() + { + $this->cli->runAsUser('composer global update'); + } } diff --git a/cli/valet.php b/cli/valet.php index 5f7d123f8..13a5c32ff 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -14,6 +14,7 @@ use Silly\Application; use Illuminate\Container\Container; +use Symfony\Component\Console\Question\ConfirmationQuestion; use function Valet\info; use function Valet\output; use function Valet\table; @@ -268,50 +269,94 @@ })->descriptions('Stop the Valet services'); /** - * Uninstall Valet entirely. + * Uninstall Valet entirely. Requires --force to actually remove; otherwise manual instructions are displayed. */ - $app->command('uninstall', function () { + $app->command('uninstall [--force]', function ($input, $output, $force) { + if ($force) { + warning('YOU ARE ABOUT TO UNINSTALL Nginx, PHP, Dnsmasq and all Valet configs and logs.'); + $helper = $this->getHelperSet()->get('question'); + $question = new ConfirmationQuestion('Are you sure you want to proceed? ', false); + if (false === $helper->ask($input, $output, $question)) { + return warning('Uninstall aborted.'); + } + info('Removing certificates for all Secured sites...'); + Site::unsecureAll(); + info('Removing Nginx and configs...'); + Nginx::uninstall(); + info('Removing Dnsmasq and configs...'); + DnsMasq::uninstall(); + info('Removing Valet configs and customizations...'); + Configuration::uninstall(); + info('Removing PHP versions and configs...'); + PhpFpm::uninstall(); + info('Attempting to unlink Valet from bin path...'); + Valet::unlinkFromUsersBin(); + info('Removing sudoers entries...'); + Brew::removeSudoersEntry(); + Valet::removeSudoersEntry(); + return output("NOTE: +Valet has attempted to uninstall itself, but there are some steps you need to do manually: +Run php -v to see what PHP version you are now really using. +Run composer global update to update your globally-installed Composer packages to work with your default PHP. +NOTE: Composer may have other dependencies for other global apps you have installed, and those may not be compatible with your default PHP. +Thus, you may need to delete things from your ~/.composer/composer.json file before running composer global update successfully. +Then to finish removing any Composer fragments of Valet: +Run composer global remove laravel/valet +and then rm /usr/local/bin/valet to remove the Valet bin link if it still exists. +Optional: +- brew list will show any other Homebrew services installed, in case you want to make changes to those as well. +- brew doctor can indicate if there might be any broken things left behind. +- brew cleanup can purge old cached Homebrew downloads. +If you had customized your Mac DNS settings in System Preferences->Network, you will need to remove 127.0.0.1 from that list. +Additionally you might also want to open Keychain Access and search for valet to remove any leftover trust certificates. +"); + } + output("WAIT! Before you uninstall things, consider cleaning things up in the following order. (Or skip to the bottom for troubleshooting suggestions.): -The uninstall of Valet is not automated, since a forced removal may delete your custom configuration information. +You did not pass the --force parameter so we are NOT ACTUALLY uninstalling anything. +A --force removal WILL delete your custom configuration information, so you will want to make backups first. + +IF YOU WANT TO UNINSTALL VALET MANUALLY, DO THE FOLLOWING... 1. Valet Keychain Certificates Before removing Valet configuration files, we recommend that you run valet unsecure --all to clean up the certificates that Valet inserted into your Keychain. -Alternatively you can do a search for @laravel.valet in KeychainAccess and delete those certificates there manually. +Alternatively you can do a search for @laravel.valet in Keychain Access and delete those certificates there manually. You may also run valet parked to see a list of all sites Valet could serve. -2. Homebrew Services +2. Valet Configuration Files +You may remove your user-specific Valet config files by running: rm -rf ~/.config/valet + +3. Remove Valet package +You can run composer global remove laravel/valet to uninstall the Valet package. + +4. Homebrew Services You may remove the core services (php, nginx, dnsmasq) by running: brew uninstall --force php nginx dnsmasq -You can then remove selected leftover configurations for these services manually in your /usr/local/etc/ subdirectory. -BEWARE: Uninstalling PHP via Homebrew will leave your Mac with its original PHP version, which may not be compatible with other composer dependencies you have installed. Thus you may get unexpected errors. +You can then remove selected leftover configurations for these services manually in both /usr/local/etc/ and /usr/local/logs/. +(If you have other PHP versions installed, run brew list | grep php to see which versions you should also uninstall manually.) -3. Valet Configuration Files -You may remove your user-specific Valet config files by running: rm -rf ~/.config/valet +BEWARE: Uninstalling PHP via Homebrew will leave your Mac with its original PHP version, which may not be compatible with other Composer dependencies you have installed. Thus you may get unexpected errors. -4. Other Housekeeping Some additional services which you may have installed (but which Valet does not directly configure or manage) include: mariadb mysql mailhog. If you wish to also remove them, you may manually run brew uninstall SERVICENAME and clean up their configurations in /usr/local/etc if necessary. -You can discover more homebrew services by running: brew services list +You can discover more Homebrew services by running: brew services list and brew list -5. Remove Valet package -You can run composer global remove laravel/valet to uninstall the Valet package. +If you have customized your Mac DNS settings in System Preferences->Network, you may need to add or remove 127.0.0.1 from the top of that list. -6. GENERAL TROUBLESHOOTING +5. GENERAL TROUBLESHOOTING If your reasons for considering an uninstall are more for troubleshooting purposes, consider running brew doctor and/or brew cleanup to see if any problems exist there. Also consider running sudo nginx -t to test your nginx configs in case there are failures/errors there preventing nginx from running. Most of the nginx configs used by Valet are in your ~/.config/valet/Nginx directory. -You might also want to investigate your global composer configs. Helpful commands there include: -composer global diagnose and composer global outdated -as well as composer global update +You might also want to investigate your global Composer configs. Helpful commands include: +composer global update to apply updates to packages +composer global outdated to indentify outdated packages +composer global diagnose to run diagnostics "); - // Stopping PHP so the ~/.config/valet/valet.sock file is released so the directory can be deleted if desired PhpFpm::stopRunning(); - - Nginx::uninstall(); // this currently only calls stop() - - })->descriptions('Uninstall the Valet services'); + Nginx::stop(); + })->descriptions('Uninstall the Valet services', ['--force' => 'Do a forceful uninstall of Valet and related Homebrew pkgs']); /** * Determine if this is the latest release of Valet.