From 539aaefd72f3dff822c684eb6e049ae0016d0ec4 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Sun, 24 Dec 2023 20:17:06 +0800 Subject: [PATCH] Add initial windows runtime setup (#292) * add initial windows runtime setup * add cool console output * doctor support windows base * add `add-path` and `remove-path` for bin/setup-runtime * fix composer.ps1 path * add windows system util * add windows cmd and doctor base check * add windows fallback for laravel/prompts * cd fix [skip ci] * dir separator and typo fix [skip ci] --- .gitignore | 7 +- bin/setup-runtime.ps1 | 115 ++++++ bin/spc.ps1 | 12 + composer.json | 1 - composer.lock | 403 +++++++++++-------- src/SPC/builder/windows/SystemUtil.php | 26 ++ src/SPC/command/BaseCommand.php | 13 + src/SPC/command/DoctorCommand.php | 5 +- src/SPC/doctor/CheckListHandler.php | 19 +- src/SPC/doctor/item/OSCheckList.php | 4 +- src/SPC/doctor/item/WindowsToolCheckList.php | 44 ++ src/SPC/util/UnixShell.php | 3 + src/SPC/util/WindowsCmd.php | 90 +++++ src/globals/defines.php | 4 + src/globals/functions.php | 6 + 15 files changed, 568 insertions(+), 184 deletions(-) create mode 100644 bin/setup-runtime.ps1 create mode 100644 bin/spc.ps1 create mode 100644 src/SPC/builder/windows/SystemUtil.php create mode 100644 src/SPC/doctor/item/WindowsToolCheckList.php create mode 100644 src/SPC/util/WindowsCmd.php diff --git a/.gitignore b/.gitignore index 1f749916..776dbffd 100644 --- a/.gitignore +++ b/.gitignore @@ -22,9 +22,12 @@ docker/source/ # exclude self-runtime /bin/* -!/bin/spc -!/bin/setup-runtime +!/bin/spc* +!/bin/setup-runtime* !/bin/spc-alpine-docker +# exclude windows build tools +/php-sdk-binary-tools/ + # default test directory /tests/var/ diff --git a/bin/setup-runtime.ps1 b/bin/setup-runtime.ps1 new file mode 100644 index 00000000..b04c3b58 --- /dev/null +++ b/bin/setup-runtime.ps1 @@ -0,0 +1,115 @@ +param ( + [string] ${action} +) + +function AddToPath { + param ( + [string]$pathToAdd + ) + + $currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User') + + if ($currentPath -notlike "*$pathToAdd*") { + $newPath = $currentPath + ";$pathToAdd" + [System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User') + Write-Host "Added '$pathToAdd' to Path." + Write-Host "To remove path, use: " -NoNewline + Write-Host "bin/setup-runtime remove-path" -ForegroundColor Cyan + } else { + Write-Host "Path already exists." + } +} + +function RemoveFromPath { + param ( + [string]$pathToRemove + ) + + $currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User') + + if ($currentPath -like "*$pathToRemove*") { + $newPath = $currentPath -replace [regex]::Escape($pathToRemove), '' + [System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User') + Write-Host "Removed Path '$pathToRemove'" + } else { + Write-Host "Path '$pathToRemove' not in Path" + } +} + +# working dir +$WorkingDir = (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Definition)) + +if ($action -eq 'add-path') { + AddToPath ($WorkingDir + '\runtime') + exit 0 +} elseif ($action -eq 'remove-path') { + RemoveFromPath ($WorkingDir + '\runtime') + exit 0 +} elseif (-not($action -eq '')) { + Write-Host ("Invalid action: " + $action) -ForegroundColor Red + exit 1 +} + +# get php 8.1 specific version +$API = (Invoke-WebRequest -Uri "https://www.php.net/releases/index.php?json&version=8.1") | ConvertFrom-Json + +# php windows download +$PHPRuntimeUrl = "https://windows.php.net/downloads/releases/php-" + $API.version + "-Win32-vs16-x64.zip" +$ComposerUrl = "https://getcomposer.org/download/latest-stable/composer.phar" + +# create dir +New-Item -Path "downloads" -ItemType Directory -Force | Out-Null + +# download php +if (-not(Test-Path "downloads\php.zip")) +{ + Write-Host "Downloading PHP ..." + Invoke-WebRequest $PHPRuntimeUrl -OutFile "downloads\php.zip" +} + +# extract php +New-Item -Path "runtime" -ItemType Directory -Force | Out-Null +Write-Host "Extracting php.zip ..." +Expand-Archive -Path "downloads/php.zip" -DestinationPath "runtime" -Force +# make php.ini +Move-Item -Path "runtime\php.ini-production" -Destination "runtime\php.ini" -Force +$OriginINI = Get-Content -Path "runtime\php.ini" -Raw +$OriginINI = $OriginINI -replace ';extension=openssl', 'extension=openssl' +$OriginINI = $OriginINI -replace ';extension=curl', 'extension=curl' +$OriginINI = $OriginINI -replace ';extension=mbstring', 'extension=mbstring' +$OriginINI = $OriginINI -replace ';extension=sodium', 'extension=sodium' +$OriginINI = $OriginINI -replace ';extension_dir = "./"', ('extension_dir = "' + (Split-Path -Parent $MyInvocation.MyCommand.Definition) + '\..\runtime\ext"') +$OriginINI | Set-Content -Path "runtime\php.ini" + +# download composer +if (-not(Test-Path "runtime\composer.phar")) +{ + Write-Host "Downloading composer ..." + Invoke-WebRequest $ComposerUrl -OutFile "downloads\composer.phar" + Move-Item -Path "downloads\composer.phar" -Destination "runtime\composer.phar" -Force +} + +# create runtime\composer.ps1 +$ComposerContent = ' +$WorkingDir = (Split-Path -Parent $MyInvocation.MyCommand.Definition) +Start-Process ($WorkingDir + "\php.exe") ($WorkingDir + "\composer.phar " + $args) -NoNewWindow -Wait +' +$ComposerContent | Set-Content -Path 'runtime\composer.ps1' -Encoding UTF8 + +Write-Host "Successfully downloaded PHP and Composer !" -ForegroundColor Green +Write-Host "Use static-php-cli: " -NoNewline +Write-Host "bin/spc" -ForegroundColor Cyan +Write-Host "Use php: " -NoNewline +Write-Host "runtime/php" -ForegroundColor Cyan +Write-Host "Use composer: " -NoNewline +Write-Host "runtime/composer" -ForegroundColor Cyan +Write-Host "" +Write-Host "Don't forget installing composer dependencies '" -NoNewline +Write-Host "runtime/composer install" -ForegroundColor Cyan -NoNewline +Write-Host "' before using static-php-cli !" +Write-Host "" +Write-Host "If you want to use this PHP for quality tools (like phpstan, php-cs-fixer) or other project," +Write-Host "or use PHP, Composer as system executable," +Write-Host "use '" -NoNewline +Write-Host "bin/setup-runtime add-path" -ForegroundColor Cyan -NoNewline +Write-Host "' to add runtime dir in Path." diff --git a/bin/spc.ps1 b/bin/spc.ps1 new file mode 100644 index 00000000..7123a880 --- /dev/null +++ b/bin/spc.ps1 @@ -0,0 +1,12 @@ +$PHP_Exec = "runtime\php.exe" + +if (-not(Test-Path $PHP_Exec)) { + $PHP_Exec = Get-Command php.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Definition + if (-not $PHP_Exec) { + Write-Host "Error: PHP not found, you need to install PHP on your system or use 'bin/setup-runtime'." -ForegroundColor Red + exit 1 + } +} + +$phpArgs = "bin\spc " + $args +Start-Process $PHP_Exec -ArgumentList $phpArgs -NoNewWindow -Wait diff --git a/composer.json b/composer.json index 2a8b4c96..a827184c 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,6 @@ "require": { "php": ">= 8.1", "ext-mbstring": "*", - "ext-pcntl": "*", "laravel/prompts": "^0.1.12", "symfony/console": "^5.4 || ^6 || ^7", "zhamao/logger": "^1.0" diff --git a/composer.lock b/composer.lock index 1be1f401..53557ee8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "198b6207aabb33778c51282cb7aa0c52", + "content-hash": "30d9cdb68b65870a63338606f68130f8", "packages": [ { "name": "illuminate/collections", - "version": "v10.33.0", + "version": "v10.38.1", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "766a3b6c3e5c8011b037a147266dcf7f93b21223" + "reference": "2677b3962a88640f92dba8a1f4ed38dcaaf13dad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/766a3b6c3e5c8011b037a147266dcf7f93b21223", - "reference": "766a3b6c3e5c8011b037a147266dcf7f93b21223", + "url": "https://api.github.com/repos/illuminate/collections/zipball/2677b3962a88640f92dba8a1f4ed38dcaaf13dad", + "reference": "2677b3962a88640f92dba8a1f4ed38dcaaf13dad", "shasum": "" }, "require": { @@ -59,11 +59,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-11-20T15:45:45+00:00" + "time": "2023-12-15T18:25:00+00:00" }, { "name": "illuminate/conditionable", - "version": "v10.33.0", + "version": "v10.38.1", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -109,7 +109,7 @@ }, { "name": "illuminate/contracts", - "version": "v10.33.0", + "version": "v10.38.1", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -157,7 +157,7 @@ }, { "name": "illuminate/macroable", - "version": "v10.33.0", + "version": "v10.38.1", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -414,16 +414,16 @@ }, { "name": "symfony/console", - "version": "v6.3.8", + "version": "v6.4.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0d14a9f6d04d4ac38a8cea1171f4554e325dae92" + "reference": "a550a7c99daeedef3f9d23fb82e3531525ff11fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0d14a9f6d04d4ac38a8cea1171f4554e325dae92", - "reference": "0d14a9f6d04d4ac38a8cea1171f4554e325dae92", + "url": "https://api.github.com/repos/symfony/console/zipball/a550a7c99daeedef3f9d23fb82e3531525ff11fd", + "reference": "a550a7c99daeedef3f9d23fb82e3531525ff11fd", "shasum": "" }, "require": { @@ -431,7 +431,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0" + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/dependency-injection": "<5.4", @@ -445,12 +445,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/lock": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -484,7 +488,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.3.8" + "source": "https://github.com/symfony/console/tree/v6.4.1" }, "funding": [ { @@ -500,7 +504,7 @@ "type": "tidelift" } ], - "time": "2023-10-31T08:09:35+00:00" + "time": "2023-11-30T10:54:28+00:00" }, { "name": "symfony/deprecation-contracts", @@ -983,16 +987,16 @@ }, { "name": "symfony/string", - "version": "v6.3.8", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "13880a87790c76ef994c91e87efb96134522577a" + "reference": "b45fcf399ea9c3af543a92edf7172ba21174d809" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/13880a87790c76ef994c91e87efb96134522577a", - "reference": "13880a87790c76ef994c91e87efb96134522577a", + "url": "https://api.github.com/repos/symfony/string/zipball/b45fcf399ea9c3af543a92edf7172ba21174d809", + "reference": "b45fcf399ea9c3af543a92edf7172ba21174d809", "shasum": "" }, "require": { @@ -1006,11 +1010,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/intl": "^6.2", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1049,7 +1053,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.3.8" + "source": "https://github.com/symfony/string/tree/v6.4.0" }, "funding": [ { @@ -1065,7 +1069,7 @@ "type": "tidelift" } ], - "time": "2023-11-09T08:28:21+00:00" + "time": "2023-11-28T20:41:49+00:00" }, { "name": "zhamao/logger", @@ -1691,29 +1695,30 @@ }, { "name": "captainhook/captainhook", - "version": "5.18.3", + "version": "5.19.2", "source": { "type": "git", "url": "https://github.com/captainhookphp/captainhook.git", - "reference": "b7bc503a40ccfe80ea9638e4921b4697669d725f" + "reference": "604bfc55fa40d6fe8c0275ca707ee80920b3b3f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/captainhookphp/captainhook/zipball/b7bc503a40ccfe80ea9638e4921b4697669d725f", - "reference": "b7bc503a40ccfe80ea9638e4921b4697669d725f", + "url": "https://api.github.com/repos/captainhookphp/captainhook/zipball/604bfc55fa40d6fe8c0275ca707ee80920b3b3f1", + "reference": "604bfc55fa40d6fe8c0275ca707ee80920b3b3f1", "shasum": "" }, "require": { + "captainhook/secrets": "^0.9.4", "ext-json": "*", "ext-spl": "*", "ext-xml": "*", - "php": ">=7.4", + "php": ">=8.0", "sebastianfeldmann/camino": "^0.9.2", "sebastianfeldmann/cli": "^3.3", "sebastianfeldmann/git": "^3.9", - "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" }, "replace": { "sebastianfeldmann/captainhook": "*" @@ -1750,7 +1755,7 @@ } ], "description": "PHP git hook manager", - "homepage": "https://github.com/captainhookphp/captainhook", + "homepage": "http://php.captainhook.info/", "keywords": [ "commit-msg", "git", @@ -1762,7 +1767,7 @@ ], "support": { "issues": "https://github.com/captainhookphp/captainhook/issues", - "source": "https://github.com/captainhookphp/captainhook/tree/5.18.3" + "source": "https://github.com/captainhookphp/captainhook/tree/5.19.2" }, "funding": [ { @@ -1770,7 +1775,7 @@ "type": "github" } ], - "time": "2023-11-05T13:56:19+00:00" + "time": "2023-12-18T14:06:12+00:00" }, { "name": "captainhook/plugin-composer", @@ -1827,6 +1832,62 @@ }, "time": "2022-01-28T04:35:22+00:00" }, + { + "name": "captainhook/secrets", + "version": "0.9.5", + "source": { + "type": "git", + "url": "https://github.com/captainhookphp/secrets.git", + "reference": "8aa90d5b9b7892abd11b9da2fc172a7b32b90cbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/captainhookphp/secrets/zipball/8aa90d5b9b7892abd11b9da2fc172a7b32b90cbe", + "reference": "8aa90d5b9b7892abd11b9da2fc172a7b32b90cbe", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "CaptainHook\\Secrets\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "Utility classes to detect secrets", + "keywords": [ + "commit-msg", + "keys", + "passwords", + "post-merge", + "prepare-commit-msg", + "secrets", + "tokens" + ], + "support": { + "issues": "https://github.com/captainhookphp/secrets/issues", + "source": "https://github.com/captainhookphp/secrets/tree/0.9.5" + }, + "funding": [ + { + "url": "https://github.com/sponsors/sebastianfeldmann", + "type": "github" + } + ], + "time": "2023-11-30T18:10:18+00:00" + }, { "name": "composer/pcre", "version": "3.1.1", @@ -2178,31 +2239,29 @@ }, { "name": "fidry/filesystem", - "version": "1.1.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theofidry/filesystem.git", - "reference": "1dd372ab3eb8b84ffe9578bff576b00c9a44ee46" + "reference": "8303225d289da1c434f6009743fbe9aad852de0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/filesystem/zipball/1dd372ab3eb8b84ffe9578bff576b00c9a44ee46", - "reference": "1dd372ab3eb8b84ffe9578bff576b00c9a44ee46", + "url": "https://api.github.com/repos/theofidry/filesystem/zipball/8303225d289da1c434f6009743fbe9aad852de0c", + "reference": "8303225d289da1c434f6009743fbe9aad852de0c", "shasum": "" }, "require": { "php": "^8.1", - "symfony/filesystem": "^6.3", + "symfony/filesystem": "^6.4 || ^7.0", "thecodingmachine/safe": "^2.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4", "ergebnis/composer-normalize": "^2.28", - "infection/infection": "^0.26", - "phpspec/prophecy-phpunit": "^2.0", + "infection/infection": ">=0.26", "phpunit/phpunit": "^10.3", - "symfony/finder": "^6.3", - "symfony/phpunit-bridge": "^6.2" + "symfony/finder": "^6.4 || ^7.0" }, "type": "library", "extra": { @@ -2235,7 +2294,7 @@ ], "support": { "issues": "https://github.com/theofidry/filesystem/issues", - "source": "https://github.com/theofidry/filesystem/tree/1.1.0" + "source": "https://github.com/theofidry/filesystem/tree/1.2.1" }, "funding": [ { @@ -2243,7 +2302,7 @@ "type": "github" } ], - "time": "2023-10-07T07:32:54+00:00" + "time": "2023-12-10T13:29:09+00:00" }, { "name": "filp/whoops", @@ -2318,16 +2377,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.40.0", + "version": "v3.41.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "27d2b3265b5d550ec411b4319967ae7cfddfb2e0" + "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/27d2b3265b5d550ec411b4319967ae7cfddfb2e0", - "reference": "27d2b3265b5d550ec411b4319967ae7cfddfb2e0", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/8b6ae8dcbaf23f09680643ab832a4a3a260265f6", + "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6", "shasum": "" }, "require": { @@ -2357,8 +2416,6 @@ "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4", - "phpspec/prophecy": "^1.17", - "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.6", "symfony/phpunit-bridge": "^6.3.8 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" @@ -2399,7 +2456,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.40.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.41.1" }, "funding": [ { @@ -2407,7 +2464,7 @@ "type": "github" } ], - "time": "2023-11-26T09:25:53+00:00" + "time": "2023-12-10T19:59:27+00:00" }, { "name": "humbug/box", @@ -2841,16 +2898,16 @@ }, { "name": "nikic/iter", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/nikic/iter.git", - "reference": "d9f88bc04b5b453914373e70c041353d8e67c3f5" + "reference": "09cd930fa9ff55747f34c7184532a5a1bd2385b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/iter/zipball/d9f88bc04b5b453914373e70c041353d8e67c3f5", - "reference": "d9f88bc04b5b453914373e70c041353d8e67c3f5", + "url": "https://api.github.com/repos/nikic/iter/zipball/09cd930fa9ff55747f34c7184532a5a1bd2385b1", + "reference": "09cd930fa9ff55747f34c7184532a5a1bd2385b1", "shasum": "" }, "require": { @@ -2887,22 +2944,22 @@ ], "support": { "issues": "https://github.com/nikic/iter/issues", - "source": "https://github.com/nikic/iter/tree/v2.3.0" + "source": "https://github.com/nikic/iter/tree/v2.4.0" }, - "time": "2023-07-25T19:55:40+00:00" + "time": "2023-12-10T20:43:19+00:00" }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -2943,9 +3000,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "nunomaduro/collision", @@ -3477,16 +3534,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.4", + "version": "1.24.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496" + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6bd0c26f3786cd9b7c359675cb789e35a8e07496", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fedf211ff14ec8381c9bf5714e33a7a552dd1acc", + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc", "shasum": "" }, "require": { @@ -3518,22 +3575,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.4" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.5" }, - "time": "2023-11-26T18:29:22+00:00" + "time": "2023-12-16T09:33:33+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.44", + "version": "1.10.50", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "bf84367c53a23f759513985c54ffe0d0c249825b" + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/bf84367c53a23f759513985c54ffe0d0c249825b", - "reference": "bf84367c53a23f759513985c54ffe0d0c249825b", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", "shasum": "" }, "require": { @@ -3582,27 +3639,27 @@ "type": "tidelift" } ], - "time": "2023-11-21T16:30:46+00:00" + "time": "2023-12-13T10:59:42+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.9", + "version": "10.1.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735" + "reference": "78c3b7625965c2513ee96569a4dbb62601784145" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a56a9ab2f680246adcf3db43f38ddf1765774735", - "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/78c3b7625965c2513ee96569a4dbb62601784145", + "reference": "78c3b7625965c2513ee96569a4dbb62601784145", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1", "phpunit/php-file-iterator": "^4.0", "phpunit/php-text-template": "^3.0", @@ -3652,7 +3709,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.11" }, "funding": [ { @@ -3660,7 +3717,7 @@ "type": "github" } ], - "time": "2023-11-23T12:23:20+00:00" + "time": "2023-12-21T15:38:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3907,16 +3964,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.4.2", + "version": "10.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1" + "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cacd8b9dd224efa8eb28beb69004126c7ca1a1a1", - "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6fce887c71076a73f32fd3e0774a6833fc5c7f19", + "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19", "shasum": "" }, "require": { @@ -3956,7 +4013,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.4-dev" + "dev-main": "10.5-dev" } }, "autoload": { @@ -3988,7 +4045,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.2" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.3" }, "funding": [ { @@ -4004,7 +4061,7 @@ "type": "tidelift" } ], - "time": "2023-10-26T07:21:45+00:00" + "time": "2023-12-13T07:25:23+00:00" }, { "name": "psr/event-dispatcher", @@ -4302,20 +4359,20 @@ }, { "name": "sebastian/complexity", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68cfb347a44871f01e33ab0ef8215966432f6957" + "reference": "68ff824baeae169ec9f2137158ee529584553799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957", - "reference": "68cfb347a44871f01e33ab0ef8215966432f6957", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", "shasum": "" }, "require": { - "nikic/php-parser": "^4.10", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1" }, "require-dev": { @@ -4324,7 +4381,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" } }, "autoload": { @@ -4348,7 +4405,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" }, "funding": [ { @@ -4356,7 +4413,7 @@ "type": "github" } ], - "time": "2023-09-28T11:50:59+00:00" + "time": "2023-12-21T08:37:17+00:00" }, { "name": "sebastian/diff", @@ -4631,20 +4688,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d" + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/649e40d279e243d985aa8fb6e74dd5bb28dc185d", - "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", "shasum": "" }, "require": { - "nikic/php-parser": "^4.10", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1" }, "require-dev": { @@ -4677,7 +4734,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.1" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" }, "funding": [ { @@ -4685,7 +4742,7 @@ "type": "github" } ], - "time": "2023-08-31T09:25:50+00:00" + "time": "2023-12-21T08:38:20+00:00" }, { "name": "sebastian/object-enumerator", @@ -5148,16 +5205,16 @@ }, { "name": "seld/jsonlint", - "version": "1.10.0", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1" + "reference": "76d449a358ece77d6f1d6331c68453e657172202" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/594fd6462aad8ecee0b45ca5045acea4776667f1", - "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/76d449a358ece77d6f1d6331c68453e657172202", + "reference": "76d449a358ece77d6f1d6331c68453e657172202", "shasum": "" }, "require": { @@ -5184,7 +5241,7 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "JSON Linter", @@ -5196,7 +5253,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.0" + "source": "https://github.com/Seldaek/jsonlint/tree/1.10.1" }, "funding": [ { @@ -5208,20 +5265,20 @@ "type": "tidelift" } ], - "time": "2023-05-11T13:16:46+00:00" + "time": "2023-12-18T13:03:25+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.3.2", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e" + "reference": "d76d2632cfc2206eecb5ad2b26cd5934082941b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e", - "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d76d2632cfc2206eecb5ad2b26cd5934082941b6", + "reference": "d76d2632cfc2206eecb5ad2b26cd5934082941b6", "shasum": "" }, "require": { @@ -5238,13 +5295,13 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/error-handler": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^5.4|^6.0" + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -5272,7 +5329,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.0" }, "funding": [ { @@ -5288,7 +5345,7 @@ "type": "tidelift" } ], - "time": "2023-07-06T06:56:43+00:00" + "time": "2023-07-27T06:52:43+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5368,16 +5425,16 @@ }, { "name": "symfony/filesystem", - "version": "v6.3.1", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" + "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/952a8cb588c3bc6ce76f6023000fb932f16a6e59", + "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59", "shasum": "" }, "require": { @@ -5411,7 +5468,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.3.1" + "source": "https://github.com/symfony/filesystem/tree/v6.4.0" }, "funding": [ { @@ -5427,27 +5484,27 @@ "type": "tidelift" } ], - "time": "2023-06-01T08:30:39+00:00" + "time": "2023-07-26T17:27:13+00:00" }, { "name": "symfony/finder", - "version": "v6.3.5", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4" + "reference": "11d736e97f116ac375a81f96e662911a34cd50ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4", - "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4", + "url": "https://api.github.com/repos/symfony/finder/zipball/11d736e97f116ac375a81f96e662911a34cd50ce", + "reference": "11d736e97f116ac375a81f96e662911a34cd50ce", "shasum": "" }, "require": { "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^6.0" + "symfony/filesystem": "^6.0|^7.0" }, "type": "library", "autoload": { @@ -5475,7 +5532,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.3.5" + "source": "https://github.com/symfony/finder/tree/v6.4.0" }, "funding": [ { @@ -5491,20 +5548,20 @@ "type": "tidelift" } ], - "time": "2023-09-26T12:56:25+00:00" + "time": "2023-10-31T17:30:12+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.3.0", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd" + "reference": "22301f0e7fdeaacc14318928612dee79be99860e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/22301f0e7fdeaacc14318928612dee79be99860e", + "reference": "22301f0e7fdeaacc14318928612dee79be99860e", "shasum": "" }, "require": { @@ -5542,7 +5599,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.3.0" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.0" }, "funding": [ { @@ -5558,20 +5615,20 @@ "type": "tidelift" } ], - "time": "2023-05-12T14:21:09+00:00" + "time": "2023-08-08T10:16:24+00:00" }, { "name": "symfony/process", - "version": "v6.3.4", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54" + "reference": "191703b1566d97a5425dc969e4350d32b8ef17aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54", - "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54", + "url": "https://api.github.com/repos/symfony/process/zipball/191703b1566d97a5425dc969e4350d32b8ef17aa", + "reference": "191703b1566d97a5425dc969e4350d32b8ef17aa", "shasum": "" }, "require": { @@ -5603,7 +5660,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.3.4" + "source": "https://github.com/symfony/process/tree/v6.4.0" }, "funding": [ { @@ -5619,11 +5676,11 @@ "type": "tidelift" } ], - "time": "2023-08-07T10:39:22+00:00" + "time": "2023-11-17T21:06:49+00:00" }, { "name": "symfony/stopwatch", - "version": "v6.3.0", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -5665,7 +5722,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.0" }, "funding": [ { @@ -5685,16 +5742,16 @@ }, { "name": "symfony/var-dumper", - "version": "v6.3.8", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "81acabba9046550e89634876ca64bfcd3c06aa0a" + "reference": "c40f7d17e91d8b407582ed51a2bbf83c52c367f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/81acabba9046550e89634876ca64bfcd3c06aa0a", - "reference": "81acabba9046550e89634876ca64bfcd3c06aa0a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c40f7d17e91d8b407582ed51a2bbf83c52c367f6", + "reference": "c40f7d17e91d8b407582ed51a2bbf83c52c367f6", "shasum": "" }, "require": { @@ -5707,10 +5764,11 @@ }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^6.3|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", "twig/twig": "^2.13|^3.0.4" }, "bin": [ @@ -5749,7 +5807,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.3.8" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.0" }, "funding": [ { @@ -5765,7 +5823,7 @@ "type": "tidelift" } ], - "time": "2023-11-08T10:42:36+00:00" + "time": "2023-11-09T08:28:32+00:00" }, { "name": "thecodingmachine/safe", @@ -6022,9 +6080,8 @@ "prefer-lowest": false, "platform": { "php": ">= 8.1", - "ext-mbstring": "*", - "ext-pcntl": "*" + "ext-mbstring": "*" }, "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.6.0" } diff --git a/src/SPC/builder/windows/SystemUtil.php b/src/SPC/builder/windows/SystemUtil.php new file mode 100644 index 00000000..b1ec35af --- /dev/null +++ b/src/SPC/builder/windows/SystemUtil.php @@ -0,0 +1,26 @@ +input = $input; $this->output = $output; + + // windows fallback + Prompt::fallbackWhen(PHP_OS_FAMILY === 'Windows'); + ConfirmPrompt::fallbackUsing(function (ConfirmPrompt $prompt) use ($input, $output) { + $helper = new QuestionHelper(); + $case = $prompt->default ? ' [Y/n] ' : ' [y/N] '; + $question = new ConfirmationQuestion($prompt->label . $case, $prompt->default); + return $helper->ask($input, $output, $question); + }); if ($this->shouldExecute()) { try { return $this->handle(); diff --git a/src/SPC/command/DoctorCommand.php b/src/SPC/command/DoctorCommand.php index 9aabdeca..bc77511a 100644 --- a/src/SPC/command/DoctorCommand.php +++ b/src/SPC/command/DoctorCommand.php @@ -75,8 +75,9 @@ class DoctorCommand extends BaseCommand } catch (\Throwable $e) { $this->output->writeln('' . $e->getMessage() . ''); - pcntl_signal(SIGINT, SIG_IGN); - + if (extension_loaded('pcntl')) { + pcntl_signal(SIGINT, SIG_IGN); + } return static::FAILURE; } diff --git a/src/SPC/doctor/CheckListHandler.php b/src/SPC/doctor/CheckListHandler.php index bfeb39c4..de5733df 100644 --- a/src/SPC/doctor/CheckListHandler.php +++ b/src/SPC/doctor/CheckListHandler.php @@ -34,12 +34,23 @@ final class CheckListHandler */ public function emitFix(OutputInterface $output, CheckResult $result): void { - pcntl_signal(SIGINT, function () use ($output) { - $output->writeln('You cancelled fix'); - }); + if (PHP_OS_FAMILY === 'Windows') { + sapi_windows_set_ctrl_handler(function () use ($output) { + $output->writeln('You cancelled fix'); + }); + } elseif (extension_loaded('pcntl')) { + pcntl_signal(SIGINT, function () use ($output) { + $output->writeln('You cancelled fix'); + }); + } $fix_result = call_user_func($this->fix_map[$result->getFixItem()], ...$result->getFixParams()); - pcntl_signal(SIGINT, SIG_IGN); + + if (PHP_OS_FAMILY === 'Windows') { + sapi_windows_set_ctrl_handler(null); + } elseif (extension_loaded('pcntl')) { + pcntl_signal(SIGINT, SIG_IGN); + } if ($fix_result) { $output->writeln('Fix done'); diff --git a/src/SPC/doctor/item/OSCheckList.php b/src/SPC/doctor/item/OSCheckList.php index ad6b2551..8c7aa762 100644 --- a/src/SPC/doctor/item/OSCheckList.php +++ b/src/SPC/doctor/item/OSCheckList.php @@ -16,8 +16,8 @@ class OSCheckList #[AsCheckItem('if current OS are supported', level: 999)] public function checkOS(): ?CheckResult { - if (!in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD'])) { - return CheckResult::fail('Current OS is not supported'); + if (!in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD', 'Windows'])) { + return CheckResult::fail('Current OS is not supported: ' . PHP_OS_FAMILY); } $distro = PHP_OS_FAMILY === 'Linux' ? (' ' . SystemUtil::getOSRelease()['dist']) : ''; return CheckResult::ok(PHP_OS_FAMILY . ' ' . php_uname('m') . $distro . ', supported'); diff --git a/src/SPC/doctor/item/WindowsToolCheckList.php b/src/SPC/doctor/item/WindowsToolCheckList.php new file mode 100644 index 00000000..73092233 --- /dev/null +++ b/src/SPC/doctor/item/WindowsToolCheckList.php @@ -0,0 +1,44 @@ +exec('git clone https://github.com/php/php-sdk-binary-tools.git ' . PHP_SDK_PATH); + } catch (RuntimeException) { + return false; + } + return true; + } +} diff --git a/src/SPC/util/UnixShell.php b/src/SPC/util/UnixShell.php index 5fd730f9..2c0ba5d1 100644 --- a/src/SPC/util/UnixShell.php +++ b/src/SPC/util/UnixShell.php @@ -17,6 +17,9 @@ class UnixShell public function __construct(?bool $debug = null) { + if (PHP_OS_FAMILY === 'Windows') { + throw new RuntimeException('Windows cannot use UnixShell'); + } $this->debug = $debug ?? defined('DEBUG_MODE'); } diff --git a/src/SPC/util/WindowsCmd.php b/src/SPC/util/WindowsCmd.php new file mode 100644 index 00000000..cf461725 --- /dev/null +++ b/src/SPC/util/WindowsCmd.php @@ -0,0 +1,90 @@ +debug = $debug ?? defined('DEBUG_MODE'); + } + + public function cd(string $dir): WindowsCmd + { + logger()->info('Entering dir: ' . $dir); + $c = clone $this; + $c->cd = $dir; + return $c; + } + + /** + * @throws RuntimeException + */ + public function exec(string $cmd): WindowsCmd + { + /* @phpstan-ignore-next-line */ + logger()->info(ConsoleColor::yellow('[EXEC] ') . ConsoleColor::green($cmd)); + if ($this->cd !== null) { + $cmd = 'cd /d ' . escapeshellarg($this->cd) . ' && ' . $cmd; + } + if (!$this->debug) { + $cmd .= ' >nul 2>&1'; + } + echo $cmd . PHP_EOL; + + f_passthru($cmd); + return $this; + } + + public function execWithResult(string $cmd, bool $with_log = true): array + { + if ($with_log) { + /* @phpstan-ignore-next-line */ + logger()->info(ConsoleColor::blue('[EXEC] ') . ConsoleColor::green($cmd)); + } else { + logger()->debug('Running command with result: ' . $cmd); + } + exec($cmd, $out, $code); + return [$code, $out]; + } + + public function setEnv(array $env): WindowsCmd + { + $this->env = array_merge($this->env, $env); + return $this; + } + + /** + * @throws RuntimeException + */ + public function execWithEnv(string $cmd): WindowsCmd + { + if ($this->getEnvString() !== '') { + return $this->exec($this->getEnvString() . "call {$cmd}"); + } + return $this->exec($cmd); + } + + private function getEnvString(): string + { + $str = ''; + foreach ($this->env as $k => $v) { + $str .= 'set ' . $k . '=' . $v . ' && '; + } + return $str; + } +} diff --git a/src/globals/defines.php b/src/globals/defines.php index 79b85406..26d2f6d7 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -22,6 +22,10 @@ define('SEPARATED_PATH', [ BUILD_ROOT_PATH, ]); +if (PHP_OS_FAMILY === 'Windows') { + define('PHP_SDK_PATH', is_string($a = getenv('PHP_SDK_PATH')) ? $a : (WORKING_DIR . DIRECTORY_SEPARATOR . 'php-sdk-binary-tools')); +} + // dangerous command const DANGER_CMD = [ 'rm', diff --git a/src/globals/functions.php b/src/globals/functions.php index d63f3350..afadf3a4 100644 --- a/src/globals/functions.php +++ b/src/globals/functions.php @@ -5,6 +5,7 @@ declare(strict_types=1); use Psr\Log\LoggerInterface; use SPC\exception\WrongUsageException; use SPC\util\UnixShell; +use SPC\util\WindowsCmd; use ZM\Logger\ConsoleLogger; /** @@ -120,3 +121,8 @@ function shell(?bool $debug = null): UnixShell { return new UnixShell($debug); } + +function cmd(?bool $debug = null): WindowsCmd +{ + return new WindowsCmd($debug); +}