diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 74d0fd4f..36cb40cd 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -151,7 +151,7 @@ jobs: run: vendor/bin/behat --tags="~@non-windows" - name: Run Behat on non-Windows if: matrix.operating-system != 'windows-latest' - run: vendor/bin/behat + run: sudo vendor/bin/behat coding-standards: runs-on: ubuntu-latest diff --git a/src/Container.php b/src/Container.php index bec580a1..ef10f42e 100644 --- a/src/Container.php +++ b/src/Container.php @@ -46,13 +46,9 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\EventDispatcher\EventDispatcher; -use function defined; -use function fopen; use function getcwd; use function str_starts_with; -use const STDIN; - /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class Container { @@ -65,14 +61,7 @@ public static function factory(): ContainerInterface static function () { $input = new ArgvInput(); - $stdin = defined('STDIN') ? STDIN : fopen('php://stdin', 'r'); - $noInteractionEnv = ComposerPlatform::getEnv('COMPOSER_NO_INTERACTION'); - if ( - $noInteractionEnv === false - || $noInteractionEnv === '1' - || $stdin === false - || ! ComposerPlatform::isTty($stdin) - ) { + if (! Platform::isInteractive()) { $input->setInteractive(false); } diff --git a/src/File/Sudo.php b/src/File/Sudo.php index b3041b40..56f61c24 100644 --- a/src/File/Sudo.php +++ b/src/File/Sudo.php @@ -4,8 +4,9 @@ namespace Php\Pie\File; +use Php\Pie\Platform; +use Php\Pie\Platform\TargetPlatform; use Symfony\Component\Process\ExecutableFinder; -use Throwable; use function is_string; @@ -29,6 +30,10 @@ public static function find(): string throw SudoNotFoundOnSystem::new(); } + if (! TargetPlatform::isRunningAsRoot() && ! Platform::isInteractive()) { + throw SudoRequiresInteractiveTerminal::fromSudo($sudo); + } + self::$memoizedSudo = $sudo; } @@ -41,7 +46,7 @@ public static function exists(): bool self::find(); return true; - } catch (Throwable) { + } catch (SudoNotFoundOnSystem) { return false; } } diff --git a/src/File/SudoRequiresInteractiveTerminal.php b/src/File/SudoRequiresInteractiveTerminal.php new file mode 100644 index 00000000..994766c5 --- /dev/null +++ b/src/File/SudoRequiresInteractiveTerminal.php @@ -0,0 +1,20 @@ +writeln(sprintf( 'Cannot write to %s, so using sudo to elevate privileges.', diff --git a/src/Platform.php b/src/Platform.php index dde3526d..9350f2b1 100644 --- a/src/Platform.php +++ b/src/Platform.php @@ -10,6 +10,8 @@ use RuntimeException; use function array_keys; +use function defined; +use function fopen; use function implode; use function md5; use function rtrim; @@ -17,10 +19,22 @@ use function strtr; use const DIRECTORY_SEPARATOR; +use const STDIN; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ class Platform { + public static function isInteractive(): bool + { + $stdin = defined('STDIN') ? STDIN : fopen('php://stdin', 'r'); + $noInteractionEnv = ComposerPlatform::getEnv('COMPOSER_NO_INTERACTION'); + + return $noInteractionEnv !== false + && $noInteractionEnv !== '1' + && $stdin !== false + && ComposerPlatform::isTty($stdin); + } + private static function useXdg(): bool { foreach (array_keys($_SERVER) as $key) {