diff --git a/bin/restore b/bin/restore index e949471fe..93b11b017 100755 --- a/bin/restore +++ b/bin/restore @@ -139,7 +139,7 @@ function createUpgradeService(array $options): SafeUpgradeService } /** - * @return list + * @return list */ function loadSnapshots(): array { @@ -160,6 +160,7 @@ function loadSnapshots(): array $snapshots[] = [ 'id' => $decoded['id'], + 'source_version' => $decoded['source_version'] ?? null, 'target_version' => $decoded['target_version'] ?? null, 'created_at' => $decoded['created_at'] ?? 0, ]; @@ -184,8 +185,8 @@ switch ($command) { echo "Available snapshots:\n"; foreach ($snapshots as $snapshot) { $time = $snapshot['created_at'] ? date('c', (int)$snapshot['created_at']) : 'unknown'; - $version = $snapshot['target_version'] ?? 'unknown'; - echo sprintf(" - %s (Grav %s, %s)\n", $snapshot['id'], $version, $time); + $restoreVersion = $snapshot['source_version'] ?? $snapshot['target_version'] ?? 'unknown'; + echo sprintf(" - %s (restore to Grav %s, %s)\n", $snapshot['id'], $restoreVersion, $time); } exit(0); @@ -209,7 +210,7 @@ switch ($command) { exit(1); } - $version = $manifest['target_version'] ?? 'unknown'; + $version = $manifest['source_version'] ?? $manifest['target_version'] ?? 'unknown'; echo "Restored snapshot {$snapshotId} (Grav {$version}).\n"; exit(0); diff --git a/system/src/Grav/Common/Upgrade/SafeUpgradeService.php b/system/src/Grav/Common/Upgrade/SafeUpgradeService.php index fbbee6714..a7385ac29 100644 --- a/system/src/Grav/Common/Upgrade/SafeUpgradeService.php +++ b/system/src/Grav/Common/Upgrade/SafeUpgradeService.php @@ -9,6 +9,7 @@ namespace Grav\Common\Upgrade; +use DirectoryIterator; use Grav\Common\Filesystem\Folder; use Grav\Common\GPM\GPM; use Grav\Common\Yaml; @@ -19,6 +20,7 @@ use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use FilesystemIterator; use function basename; +use function copy; use function count; use function dirname; use function file_get_contents; @@ -165,6 +167,8 @@ class SafeUpgradeService // Copy extracted package into staging area. Folder::rcopy($extractedPath, $packagePath); + $this->carryOverRootDotfiles($packagePath); + // Ensure ignored directories are replaced with live copies. $this->hydrateIgnoredDirectories($packagePath, $ignores); @@ -375,6 +379,49 @@ class SafeUpgradeService } } + /** + * Preserve critical root-level dotfiles that may not ship in update packages. + * + * @param string $packagePath + * @return void + */ + private function carryOverRootDotfiles(string $packagePath): void + { + $skip = [ + '.git', + '.DS_Store', + ]; + + $iterator = new DirectoryIterator($this->rootPath); + foreach ($iterator as $entry) { + if ($entry->isDot()) { + continue; + } + + $name = $entry->getFilename(); + if ($name === '' || $name[0] !== '.') { + continue; + } + + if (in_array($name, $skip, true)) { + continue; + } + + $target = $packagePath . DIRECTORY_SEPARATOR . $name; + if (file_exists($target)) { + continue; + } + + $source = $entry->getPathname(); + if ($entry->isDir()) { + Folder::rcopy($source, $target); + } elseif ($entry->isFile()) { + Folder::create(dirname($target)); + copy($source, $target); + } + } + } + /** * Build manifest metadata for a staged upgrade. *