-
Notifications
You must be signed in to change notification settings - Fork 710
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1216 from NasirNobin/feature/valet-run
PHP version isolation helper for command line
- Loading branch information
Showing
6 changed files
with
272 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
namespace Valet; | ||
|
||
use DomainException; | ||
use PhpFpm; | ||
|
||
class Brew | ||
{ | ||
|
@@ -264,16 +265,7 @@ public function getParsedLinkedPhp() | |
|
||
$resolvedPath = $this->files->readLink(BREW_PREFIX.'/bin/php'); | ||
|
||
/** | ||
* Typical homebrew path resolutions are like: | ||
* "../Cellar/[email protected]/7.4.13/bin/php" | ||
* or older styles: | ||
* "../Cellar/php/7.4.9_2/bin/php | ||
* "../Cellar/php55/bin/php. | ||
*/ | ||
preg_match('~\w{3,}/(php)(@?\d\.?\d)?/(\d\.\d)?([_\d\.]*)?/?\w{3,}~', $resolvedPath, $matches); | ||
|
||
return $matches; | ||
return $this->parsePhpPath($resolvedPath); | ||
} | ||
|
||
/** | ||
|
@@ -302,15 +294,51 @@ public function linkedPhp() | |
|
||
return $this->supportedPhpVersions()->first( | ||
function ($version) use ($resolvedPhpVersion) { | ||
$resolvedVersionNormalized = preg_replace('/[^\d]/', '', $resolvedPhpVersion); | ||
$versionNormalized = preg_replace('/[^\d]/', '', $version); | ||
|
||
return $resolvedVersionNormalized === $versionNormalized; | ||
return $this->arePhpVersionsEqual($resolvedPhpVersion, $version); | ||
}, function () use ($resolvedPhpVersion) { | ||
throw new DomainException("Unable to determine linked PHP when parsing '$resolvedPhpVersion'"); | ||
}); | ||
} | ||
|
||
/** | ||
* Extract PHP executable path from PHP Version. | ||
* | ||
* @param string $phpVersion For example, "[email protected]" | ||
* @return string | ||
*/ | ||
public function getPhpExecutablePath($phpVersion = null) | ||
{ | ||
if (! $phpVersion) { | ||
return BREW_PREFIX.'/bin/php'; | ||
} | ||
|
||
$phpVersion = PhpFpm::normalizePhpVersion($phpVersion); | ||
|
||
// Check the default `/opt/homebrew/opt/[email protected]/bin/php` location first | ||
if ($this->files->exists(BREW_PREFIX."/opt/{$phpVersion}/bin/php")) { | ||
return BREW_PREFIX."/opt/{$phpVersion}/bin/php"; | ||
} | ||
|
||
// Check the `/opt/homebrew/opt/php71/bin/php` location for older installations | ||
$phpVersion = str_replace(['@', '.'], '', $phpVersion); // [email protected] to php81 | ||
if ($this->files->exists(BREW_PREFIX."/opt/{$phpVersion}/bin/php")) { | ||
return BREW_PREFIX."/opt/{$phpVersion}/bin/php"; | ||
} | ||
|
||
// Check if the default PHP is the version we are looking for | ||
if ($this->files->isLink(BREW_PREFIX.'/opt/php')) { | ||
$resolvedPath = $this->files->readLink(BREW_PREFIX.'/opt/php'); | ||
$matches = $this->parsePhpPath($resolvedPath); | ||
$resolvedPhpVersion = $matches[3] ?: $matches[2]; | ||
|
||
if ($this->arePhpVersionsEqual($resolvedPhpVersion, $phpVersion)) { | ||
return BREW_PREFIX.'/opt/php/bin/php'; | ||
} | ||
} | ||
|
||
return BREW_PREFIX.'/bin/php'; | ||
} | ||
|
||
/** | ||
* Restart the linked PHP-FPM Homebrew service. | ||
* | ||
|
@@ -476,4 +504,39 @@ function ($exitCode, $errorOutput) { | |
} | ||
); | ||
} | ||
|
||
/** | ||
* Parse homebrew PHP Path. | ||
* | ||
* @param string $resolvedPath | ||
* @return array | ||
*/ | ||
public function parsePhpPath($resolvedPath) | ||
{ | ||
/** | ||
* Typical homebrew path resolutions are like: | ||
* "../Cellar/[email protected]/7.4.13/bin/php" | ||
* or older styles: | ||
* "../Cellar/php/7.4.9_2/bin/php | ||
* "../Cellar/php55/bin/php. | ||
*/ | ||
preg_match('~\w{3,}/(php)(@?\d\.?\d)?/(\d\.\d)?([_\d\.]*)?/?\w{3,}~', $resolvedPath, $matches); | ||
|
||
return $matches; | ||
} | ||
|
||
/** | ||
* Check if two PHP versions are equal. | ||
* | ||
* @param string $versionA | ||
* @param string $versionB | ||
* @return bool | ||
*/ | ||
public function arePhpVersionsEqual($versionA, $versionB) | ||
{ | ||
$versionANormalized = preg_replace('/[^\d]/', '', $versionA); | ||
$versionBNormalized = preg_replace('/[^\d]/', '', $versionB); | ||
|
||
return $versionANormalized === $versionBNormalized; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -398,6 +398,71 @@ public function test_restart_linked_php_will_pass_through_linked_php_formula_to_ | |
$brewMock->restartLinkedPhp(); | ||
} | ||
|
||
public function test_it_can_get_php_binary_path_from_php_version() | ||
{ | ||
// Check the default `/opt/homebrew/opt/[email protected]/bin/php` location first | ||
$brewMock = Mockery::mock(Brew::class, [ | ||
Mockery::mock(CommandLine::class), | ||
$files = Mockery::mock(Filesystem::class), | ||
])->makePartial(); | ||
|
||
$files->shouldReceive('exists')->once()->with(BREW_PREFIX.'/opt/[email protected]/bin/php')->andReturn(true); | ||
$files->shouldNotReceive('exists')->with(BREW_PREFIX.'/opt/php@74/bin/php'); | ||
$this->assertEquals(BREW_PREFIX.'/opt/[email protected]/bin/php', $brewMock->getPhpExecutablePath('[email protected]')); | ||
|
||
// Check the `/opt/homebrew/opt/php71/bin/php` location for older installations | ||
$brewMock = Mockery::mock(Brew::class, [ | ||
Mockery::mock(CommandLine::class), | ||
$files = Mockery::mock(Filesystem::class), | ||
])->makePartial(); | ||
|
||
$files->shouldReceive('exists')->once()->with(BREW_PREFIX.'/opt/[email protected]/bin/php')->andReturn(false); | ||
$files->shouldReceive('exists')->with(BREW_PREFIX.'/opt/php74/bin/php')->andReturn(true); | ||
$this->assertEquals(BREW_PREFIX.'/opt/php74/bin/php', $brewMock->getPhpExecutablePath('[email protected]')); | ||
|
||
// When the default PHP is the version we are looking for | ||
$brewMock = Mockery::mock(Brew::class, [ | ||
Mockery::mock(CommandLine::class), | ||
$files = Mockery::mock(Filesystem::class), | ||
])->makePartial(); | ||
|
||
$files->shouldReceive('exists')->once()->with(BREW_PREFIX.'/opt/[email protected]/bin/php')->andReturn(false); | ||
$files->shouldReceive('exists')->with(BREW_PREFIX.'/opt/php74/bin/php')->andReturn(false); | ||
$files->shouldReceive('isLink')->with(BREW_PREFIX.'/opt/php')->andReturn(true); | ||
$files->shouldReceive('readLink')->with(BREW_PREFIX.'/opt/php')->andReturn('../Cellar/[email protected]/7.4.13/bin/php'); | ||
$this->assertEquals(BREW_PREFIX.'/opt/php/bin/php', $brewMock->getPhpExecutablePath('[email protected]')); | ||
|
||
// When the default PHP is not the version we are looking for | ||
$brewMock = Mockery::mock(Brew::class, [ | ||
Mockery::mock(CommandLine::class), | ||
$files = Mockery::mock(Filesystem::class), | ||
])->makePartial(); | ||
|
||
$files->shouldReceive('exists')->once()->with(BREW_PREFIX.'/opt/[email protected]/bin/php')->andReturn(false); | ||
$files->shouldReceive('exists')->with(BREW_PREFIX.'/opt/php74/bin/php')->andReturn(false); | ||
$files->shouldReceive('isLink')->with(BREW_PREFIX.'/opt/php')->andReturn(true); | ||
$files->shouldReceive('readLink')->with(BREW_PREFIX.'/opt/php')->andReturn('../Cellar/[email protected]/8.1.13/bin/php'); | ||
$this->assertEquals(BREW_PREFIX.'/bin/php', $brewMock->getPhpExecutablePath('[email protected]')); // Could not find a version, so retuned the default binary | ||
|
||
// When no PHP Version is provided | ||
$brewMock = Mockery::mock(Brew::class, [ | ||
Mockery::mock(CommandLine::class), | ||
Mockery::mock(Filesystem::class), | ||
])->makePartial(); | ||
|
||
$this->assertEquals(BREW_PREFIX.'/bin/php', $brewMock->getPhpExecutablePath(null)); | ||
} | ||
|
||
public function test_it_can_compare_two_php_versions() | ||
{ | ||
$this->assertTrue(resolve(Brew::class)->arePhpVersionsEqual('php71', '[email protected]')); | ||
$this->assertTrue(resolve(Brew::class)->arePhpVersionsEqual('php71', 'php@71')); | ||
$this->assertTrue(resolve(Brew::class)->arePhpVersionsEqual('php71', '71')); | ||
|
||
$this->assertFalse(resolve(Brew::class)->arePhpVersionsEqual('php71', 'php@70')); | ||
$this->assertFalse(resolve(Brew::class)->arePhpVersionsEqual('php71', '72')); | ||
} | ||
|
||
/** | ||
* Provider of php links and their expected split matches. | ||
* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -819,6 +819,55 @@ public function test_it_returns_secured_sites() | |
|
||
$this->assertSame(['helloworld.tld'], $sites); | ||
} | ||
|
||
public function test_it_can_read_php_rc_version() | ||
{ | ||
$config = Mockery::mock(Configuration::class); | ||
$files = Mockery::mock(Filesystem::class); | ||
|
||
swap(Configuration::class, $config); | ||
swap(Filesystem::class, $files); | ||
|
||
$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/some-other-directory/site2', | ||
], | ||
])); | ||
|
||
$files->shouldReceive('exists')->with('/Users/name/code/site1/.valetphprc')->andReturn(true); | ||
$files->shouldReceive('get')->with('/Users/name/code/site1/.valetphprc')->andReturn('[email protected]'); | ||
|
||
$files->shouldReceive('exists')->with('/Users/name/some-other-directory/site2/.valetphprc')->andReturn(true); | ||
$files->shouldReceive('get')->with('/Users/name/some-other-directory/site2/.valetphprc')->andReturn('[email protected]'); | ||
|
||
$this->assertEquals('[email protected]', $siteMock->phpRcVersion('site1')); | ||
$this->assertEquals('[email protected]', $siteMock->phpRcVersion('site2')); | ||
$this->assertEquals(null, $siteMock->phpRcVersion('site3')); // Site doesn't exists | ||
} | ||
} | ||
|
||
class CommandLineFake extends CommandLine | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters