diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index 67c77362d..c90bb2d5f 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -1614,14 +1614,6 @@ form: validate: type: bool - updates.staging_root: - type: text - label: PLUGIN_ADMIN.SAFE_UPGRADE_STAGING - help: PLUGIN_ADMIN.SAFE_UPGRADE_STAGING_HELP - placeholder: '/absolute/path/to/grav-upgrades' - validate: - type: string - http_section: type: section title: PLUGIN_ADMIN.HTTP_SECTION @@ -1936,4 +1928,3 @@ form: # # pages.type: # type: hidden - diff --git a/system/config/system.yaml b/system/config/system.yaml index 50cbcd28f..87b6d4c1c 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -205,7 +205,6 @@ gpm: updates: safe_upgrade: true # Enable guarded staging+rollback pipeline for Grav self-updates - staging_root: '' # Optional absolute path for staging backups (default: /grav-upgrades) http: method: auto # Either 'curl', 'fopen' or 'auto'. 'auto' will try fopen first and if not available cURL diff --git a/system/languages/en.yaml b/system/languages/en.yaml index 973199ff3..3b34a93db 100644 --- a/system/languages/en.yaml +++ b/system/languages/en.yaml @@ -124,5 +124,3 @@ PLUGIN_ADMIN: UPDATES_SECTION: Updates SAFE_UPGRADE: Safe self-upgrade SAFE_UPGRADE_HELP: When enabled, Grav core updates use staged installation with automatic rollback support. - SAFE_UPGRADE_STAGING: Staging directory - SAFE_UPGRADE_STAGING_HELP: Optional absolute path for storing upgrade backups. Leave empty to use the default inside the parent directory. diff --git a/system/src/Grav/Common/Upgrade/SafeUpgradeService.php b/system/src/Grav/Common/Upgrade/SafeUpgradeService.php index fe781880b..fe43a5147 100644 --- a/system/src/Grav/Common/Upgrade/SafeUpgradeService.php +++ b/system/src/Grav/Common/Upgrade/SafeUpgradeService.php @@ -12,6 +12,7 @@ namespace Grav\Common\Upgrade; use DirectoryIterator; use Grav\Common\Filesystem\Folder; use Grav\Common\GPM\GPM; +use Grav\Common\Grav; use Grav\Common\Yaml; use InvalidArgumentException; use RuntimeException; @@ -83,27 +84,30 @@ class SafeUpgradeService $this->parentDir = $options['parent_dir'] ?? dirname($this->rootPath); $this->config = $options['config'] ?? null; - $candidates = []; - if (!empty($options['staging_root'])) { - $candidates[] = $options['staging_root']; + $locator = null; + try { + $locator = Grav::instance()['locator'] ?? null; + } catch (Throwable $e) { + $locator = null; } - $candidates[] = $this->parentDir . DIRECTORY_SEPARATOR . 'grav-upgrades'; - if (getenv('HOME')) { - $candidates[] = getenv('HOME') . DIRECTORY_SEPARATOR . 'grav-upgrades'; - } - $candidates[] = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'grav-upgrades'; - $this->stagingRoot = null; - foreach ($candidates as $candidate) { - $resolved = $this->resolveStagingPath($candidate); - if ($resolved) { - $this->stagingRoot = $resolved; - break; + $primary = null; + if ($locator && method_exists($locator, 'findResource')) { + try { + $primary = $locator->findResource('tmp://grav-upgrades', true, true); + } catch (Throwable $e) { + $primary = null; } } + if (!$primary) { + $primary = $this->rootPath . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'grav-upgrades'; + } + + $this->stagingRoot = $this->resolveStagingPath($primary); + if (null === $this->stagingRoot) { - throw new RuntimeException('Unable to locate writable staging directory. Configure system.updates.staging_root or adjust permissions.'); + throw new RuntimeException('Unable to locate writable staging directory. Ensure tmp://grav-upgrades is writable.'); } $this->manifestStore = $options['manifest_store'] ?? ($this->rootPath . DIRECTORY_SEPARATOR . 'user' . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'upgrades'); if (isset($options['ignored_dirs']) && is_array($options['ignored_dirs'])) { @@ -671,6 +675,8 @@ class SafeUpgradeService $home = getenv('HOME'); if ($home) { $expanded = rtrim($home, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ltrim($expanded, '~\/'); + } else { + return null; } } if (!$this->isAbsolutePath($expanded)) { diff --git a/system/src/Grav/Console/Gpm/SelfupgradeCommand.php b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php index 109028247..e98fb15da 100644 --- a/system/src/Grav/Console/Gpm/SelfupgradeCommand.php +++ b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php @@ -292,10 +292,8 @@ class SelfupgradeCommand extends GpmCommand $config = null; } - $stagingRoot = $config ? $config->get('system.updates.staging_root') : null; - return new SafeUpgradeService([ - 'staging_root' => $stagingRoot, + 'config' => $config, ]); } diff --git a/system/src/Grav/Installer/Install.php b/system/src/Grav/Installer/Install.php index 794e6f67e..e9c59b6e9 100644 --- a/system/src/Grav/Installer/Install.php +++ b/system/src/Grav/Installer/Install.php @@ -266,7 +266,7 @@ ERR; try { $grav = Grav::instance(); if ($grav && isset($grav['config'])) { - $options['staging_root'] = $grav['config']->get('system.updates.staging_root'); + $options['config'] = $grav['config']; } } catch (\Throwable $e) { // ignore diff --git a/tests/unit/Grav/Common/Upgrade/SafeUpgradeServiceTest.php b/tests/unit/Grav/Common/Upgrade/SafeUpgradeServiceTest.php index b69bef31e..e46cbb65a 100644 --- a/tests/unit/Grav/Common/Upgrade/SafeUpgradeServiceTest.php +++ b/tests/unit/Grav/Common/Upgrade/SafeUpgradeServiceTest.php @@ -94,7 +94,6 @@ class SafeUpgradeServiceTest extends \Codeception\TestCase\Test [$root, $staging, $manifestStore] = $this->prepareLiveEnvironment(); $service = new SafeUpgradeService([ 'root' => $root, - 'staging_root' => $staging, 'manifest_store' => $manifestStore, ]); @@ -121,7 +120,6 @@ class SafeUpgradeServiceTest extends \Codeception\TestCase\Test [$root, $staging, $manifestStore] = $this->prepareLiveEnvironment(); $service = new SafeUpgradeService([ 'root' => $root, - 'staging_root' => $staging, 'manifest_store' => $manifestStore, ]); @@ -147,7 +145,6 @@ class SafeUpgradeServiceTest extends \Codeception\TestCase\Test $service = new SafeUpgradeService([ 'root' => $root, - 'staging_root' => $this->tmpDir . '/staging', ]); $method = new ReflectionMethod(SafeUpgradeService::class, 'detectPsrLogConflicts'); @@ -176,7 +173,6 @@ PHP; $service = new SafeUpgradeService([ 'root' => $root, - 'staging_root' => $this->tmpDir . '/staging', ]); $method = new ReflectionMethod(SafeUpgradeService::class, 'detectMonologConflicts'); @@ -197,7 +193,6 @@ PHP; $service = new SafeUpgradeService([ 'root' => $root, - 'staging_root' => $this->tmpDir . '/staging', ]); $service->clearRecoveryFlag(); @@ -210,7 +205,7 @@ PHP; private function prepareLiveEnvironment(): array { $root = $this->tmpDir . '/root'; - $staging = $this->tmpDir . '/staging'; + $staging = $root . '/tmp/grav-upgrades'; $manifestStore = $root . '/user/data/upgrades'; Folder::create($root . '/user/plugins/sample');