Skip to content

Commit 3e75027

Browse files
authored
Merge pull request #638 from asgrim/579-merge-up-brew-self-update
579: merge up brew self update
2 parents ad606a1 + bfe6450 commit 3e75027

3 files changed

Lines changed: 136 additions & 1 deletion

File tree

src/Command/SelfUpdateCommand.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Php\Pie\Platform;
1515
use Php\Pie\SelfManage\Update\Channel;
1616
use Php\Pie\SelfManage\Update\FetchPieReleaseFromGitHub;
17+
use Php\Pie\SelfManage\Update\IsBrewInstallation;
1718
use Php\Pie\SelfManage\Update\ReleaseIsNewer;
1819
use Php\Pie\SelfManage\Update\ReleaseMetadata;
1920
use Php\Pie\SelfManage\Verify\FailedToVerifyRelease;
@@ -30,7 +31,9 @@
3031
use Symfony\Component\Console\Output\OutputInterface;
3132
use Throwable;
3233

34+
use function is_link;
3335
use function Safe\file_get_contents;
36+
use function Safe\realpath;
3437
use function Safe\unlink;
3538
use function sprintf;
3639

@@ -88,6 +91,15 @@ public function execute(InputInterface $input, OutputInterface $output): int
8891
return Command::FAILURE;
8992
}
9093

94+
$originalPathToSelf = ($this->fullPathToSelf)();
95+
$fullPathToSelf = is_link($originalPathToSelf) ? (realpath($originalPathToSelf) ?: $originalPathToSelf) : $originalPathToSelf;
96+
97+
if ((new IsBrewInstallation())($fullPathToSelf, $originalPathToSelf)) {
98+
$this->io->writeError('<comment>Aborting! PIE was installed with Brew, you should upgrade with `brew upgrade pie`.</comment>');
99+
100+
return Command::FAILURE;
101+
}
102+
91103
$settings = new Settings(Platform::getPieBaseWorkingDirectory());
92104
$updateChannel = $settings->updateChannel();
93105

@@ -198,7 +210,6 @@ public function execute(InputInterface $input, OutputInterface $output): int
198210
return Command::FAILURE;
199211
}
200212

201-
$fullPathToSelf = ($this->fullPathToSelf)();
202213
$this->io->write(
203214
sprintf('Writing new version to %s', $fullPathToSelf),
204215
verbosity: IOInterface::VERBOSE,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Php\Pie\SelfManage\Update;
6+
7+
use function str_contains;
8+
9+
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
10+
final class IsBrewInstallation
11+
{
12+
public function __invoke(string $resolvedPath, string $originalPath): bool
13+
{
14+
return str_contains($resolvedPath, '/usr/local/Cellar')
15+
|| str_contains($resolvedPath, '/opt/homebrew/Cellar')
16+
|| str_contains($originalPath, '/usr/local/Cellar')
17+
|| str_contains($originalPath, '/opt/homebrew/Cellar');
18+
}
19+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Php\PieUnitTest\SelfManage\Update;
6+
7+
use Composer\Util\Filesystem;
8+
use Php\Pie\SelfManage\Update\IsBrewInstallation;
9+
use PHPUnit\Framework\Attributes\CoversClass;
10+
use PHPUnit\Framework\Attributes\DataProvider;
11+
use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily;
12+
use PHPUnit\Framework\TestCase;
13+
14+
use function Safe\mkdir;
15+
use function Safe\realpath;
16+
use function Safe\symlink;
17+
use function Safe\touch;
18+
use function sys_get_temp_dir;
19+
use function uniqid;
20+
21+
use const DIRECTORY_SEPARATOR;
22+
23+
#[CoversClass(IsBrewInstallation::class)]
24+
final class IsBrewInstallationTest extends TestCase
25+
{
26+
/** @return array<non-empty-string, array{0: string, 1: string, 2: bool}> */
27+
public static function pathProvider(): array
28+
{
29+
return [
30+
'regular-path' => ['/home/user/.local/bin/pie.phar', '/home/user/.local/bin/pie.phar', false],
31+
'both-regular-usr-local' => ['/usr/local/bin/pie', '/usr/local/bin/pie', false],
32+
'intel-mac-cellar-direct' => ['/usr/local/Cellar/pie/1.0/bin/pie', '/usr/local/Cellar/pie/1.0/bin/pie', true],
33+
'apple-silicon-cellar-direct' => ['/opt/homebrew/Cellar/pie/1.0/bin/pie', '/opt/homebrew/Cellar/pie/1.0/bin/pie', true],
34+
'resolved-is-cellar' => ['/opt/homebrew/Cellar/pie/1.0/bin/pie', '/usr/local/bin/pie', true],
35+
'original-is-cellar' => ['/usr/local/bin/pie', '/opt/homebrew/Cellar/pie/1.0/bin/pie', true],
36+
];
37+
}
38+
39+
#[DataProvider('pathProvider')]
40+
public function testIsBrewInstallationWithPaths(
41+
string $resolvedPath,
42+
string $originalPath,
43+
bool $expected,
44+
): void {
45+
self::assertSame($expected, (new IsBrewInstallation())($resolvedPath, $originalPath));
46+
}
47+
48+
#[RequiresOperatingSystemFamily('Linux')]
49+
public function testSymlinkAtRegularPathPointingIntoBrewCellarIsDetected(): void
50+
{
51+
$tmpDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('pie_brew_test_', true);
52+
$cellarFile = $tmpDir . '/opt/homebrew/Cellar/pie/1.0/pie.phar';
53+
$symlinkPath = $tmpDir . '/pie';
54+
55+
mkdir($tmpDir . '/opt/homebrew/Cellar/pie/1.0', 0777, true);
56+
touch($cellarFile);
57+
symlink($cellarFile, $symlinkPath);
58+
59+
try {
60+
$resolvedPath = realpath($symlinkPath);
61+
self::assertTrue((new IsBrewInstallation())($resolvedPath, $symlinkPath));
62+
} finally {
63+
(new Filesystem())->remove($tmpDir);
64+
}
65+
}
66+
67+
#[RequiresOperatingSystemFamily('Linux')]
68+
public function testSymlinkAtRegularPathPointingToNonBrewPathIsNotDetected(): void
69+
{
70+
$tmpDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('pie_brew_test_', true);
71+
$regularFile = $tmpDir . '/regular/pie.phar';
72+
$symlinkPath = $tmpDir . '/pie';
73+
74+
mkdir($tmpDir . '/regular', 0777, true);
75+
touch($regularFile);
76+
symlink($regularFile, $symlinkPath);
77+
78+
try {
79+
$resolvedPath = realpath($symlinkPath);
80+
self::assertFalse((new IsBrewInstallation())($resolvedPath, $symlinkPath));
81+
} finally {
82+
(new Filesystem())->remove($tmpDir);
83+
}
84+
}
85+
86+
#[RequiresOperatingSystemFamily('Linux')]
87+
public function testSymlinkInCellarPointingToRegularPathIsDetectedViaOriginalPath(): void
88+
{
89+
$tmpDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('pie_brew_test_', true);
90+
$regularFile = $tmpDir . '/regular/pie.phar';
91+
$symlinkPath = $tmpDir . '/opt/homebrew/Cellar/pie/1.0/pie';
92+
93+
mkdir($tmpDir . '/regular', 0777, true);
94+
mkdir($tmpDir . '/opt/homebrew/Cellar/pie/1.0', 0777, true);
95+
touch($regularFile);
96+
symlink($regularFile, $symlinkPath);
97+
98+
try {
99+
$resolvedPath = realpath($symlinkPath);
100+
self::assertTrue((new IsBrewInstallation())($resolvedPath, $symlinkPath));
101+
} finally {
102+
(new Filesystem())->remove($tmpDir);
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)