staging root config option

Signed-off-by: Andy Miller <rhuk@mac.com>
This commit is contained in:
Andy Miller
2025-10-15 13:00:05 -06:00
parent cf2ac28be2
commit 7dd5c8a0ba
4 changed files with 38 additions and 5 deletions

View File

@@ -1614,6 +1614,14 @@ 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
@@ -1929,4 +1937,3 @@ form:
# pages.type:
# type: hidden

View File

@@ -205,6 +205,7 @@ gpm:
updates:
safe_upgrade: true # Enable guarded staging+rollback pipeline for Grav self-updates
staging_root: '' # Optional absolute path for staging backups (default: <grav parent>/grav-upgrades)
http:
method: auto # Either 'curl', 'fopen' or 'auto'. 'auto' will try fopen first and if not available cURL

View File

@@ -124,3 +124,5 @@ 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.

View File

@@ -76,10 +76,12 @@ class SafeUpgradeService
$this->rootPath = rtrim($root, DIRECTORY_SEPARATOR);
$this->parentDir = $options['parent_dir'] ?? dirname($this->rootPath);
$defaultStaging = $options['staging_root'] ?? ($this->parentDir . DIRECTORY_SEPARATOR . 'grav-upgrades');
try {
Folder::create($defaultStaging);
} catch (\RuntimeException $e) {
throw new RuntimeException(sprintf('Unable to create staging directory at %s. Adjust permissions or configure system.updates.staging_root.', $defaultStaging));
if (!$this->ensureWritable($defaultStaging)) {
$fallback = getenv('HOME') ? getenv('HOME') . DIRECTORY_SEPARATOR . 'grav-upgrades' : sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'grav-upgrades';
if (!$this->ensureWritable($fallback)) {
throw new RuntimeException(sprintf('Unable to create staging directory at %s or fallback %s. Adjust permissions or configure system.updates.staging_root.', $defaultStaging, $fallback));
}
$defaultStaging = $fallback;
}
$this->stagingRoot = realpath($defaultStaging) ?: $defaultStaging;
$this->manifestStore = $options['manifest_store'] ?? ($this->rootPath . DIRECTORY_SEPARATOR . 'user' . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'upgrades');
@@ -501,6 +503,27 @@ class SafeUpgradeService
file_put_contents($target, json_encode($manifest, JSON_PRETTY_PRINT));
}
/**
* Ensure directory exists and is writable.
*
* @param string $path
* @return bool
*/
private function ensureWritable(string $path): bool
{
try {
Folder::create($path);
} catch (\RuntimeException $e) {
return false;
}
if (!is_writable($path)) {
return false;
}
return true;
}
/**
* @param string|null $id
* @return array|null