mirror of
https://github.com/getgrav/grav.git
synced 2025-12-05 15:29:57 +01:00
added back snapshots in Install.php
Signed-off-by: Andy Miller <rhuk@mac.com>
This commit is contained in:
@@ -333,6 +333,51 @@ class SafeUpgradeService
|
||||
return $manifest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a snapshot specifically for automated upgrades.
|
||||
*
|
||||
* @param string $targetVersion
|
||||
* @param string|null $label
|
||||
* @return array
|
||||
*/
|
||||
public function createUpgradeSnapshot(string $targetVersion, ?string $label = null): array
|
||||
{
|
||||
$entries = $this->collectPackageEntries($this->rootPath);
|
||||
if (!$entries) {
|
||||
throw new RuntimeException('Unable to locate files to snapshot.');
|
||||
}
|
||||
|
||||
$stageId = uniqid('upgrade-', false);
|
||||
$backupPath = $this->stagingRoot . DIRECTORY_SEPARATOR . 'snapshot-' . $stageId;
|
||||
|
||||
$this->reportProgress('snapshot', sprintf('Capturing snapshot before upgrading to %s...', $targetVersion), null, [
|
||||
'operation' => 'upgrade',
|
||||
'target_version' => $targetVersion,
|
||||
]);
|
||||
|
||||
$this->createBackupSnapshot($entries, $backupPath);
|
||||
|
||||
$manifest = $this->buildManifest($stageId, $targetVersion, $this->rootPath, $backupPath, $entries);
|
||||
$manifest['package_path'] = null;
|
||||
if ($label !== null && $label !== '') {
|
||||
$manifest['label'] = $label;
|
||||
}
|
||||
$manifest['operation'] = 'upgrade';
|
||||
$manifest['mode'] = 'pre-upgrade';
|
||||
|
||||
$this->persistManifest($manifest);
|
||||
$this->lastManifest = $manifest;
|
||||
$this->pruneOldSnapshots();
|
||||
|
||||
$this->reportProgress('snapshot', sprintf('Snapshot %s captured.', $stageId), 100, [
|
||||
'operation' => 'upgrade',
|
||||
'snapshot' => $stageId,
|
||||
'target_version' => $targetVersion,
|
||||
]);
|
||||
|
||||
return $manifest;
|
||||
}
|
||||
|
||||
private function collectPackageEntries(string $packagePath): array
|
||||
{
|
||||
$entries = [];
|
||||
|
||||
@@ -12,14 +12,31 @@ namespace Grav\Installer;
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Exception;
|
||||
use Grav\Common\Cache;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\GPM\Installer;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Plugins;
|
||||
use RuntimeException;
|
||||
use function class_exists;
|
||||
use function date;
|
||||
use function dirname;
|
||||
use function floor;
|
||||
use function function_exists;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function is_link;
|
||||
use function is_string;
|
||||
use function is_writable;
|
||||
use function json_encode;
|
||||
use function readlink;
|
||||
use function sort;
|
||||
use function sprintf;
|
||||
use function symlink;
|
||||
use function time;
|
||||
use function uniqid;
|
||||
use function unlink;
|
||||
use const GRAV_ROOT;
|
||||
use const JSON_PRETTY_PRINT;
|
||||
|
||||
/**
|
||||
* Grav installer.
|
||||
@@ -295,6 +312,16 @@ ERR;
|
||||
$this->updater->install();
|
||||
|
||||
$safeUpgradeRequested = $this->shouldUseSafeUpgrade();
|
||||
$targetVersion = $this->getVersion();
|
||||
$snapshotManifest = null;
|
||||
if ($safeUpgradeRequested) {
|
||||
$snapshotManifest = $this->captureCoreSnapshot($targetVersion);
|
||||
if ($snapshotManifest) {
|
||||
$this->relayProgress('snapshot', sprintf('Snapshot %s captured.', $snapshotManifest['id']), 100);
|
||||
} else {
|
||||
$this->relayProgress('snapshot', 'Snapshot capture unavailable; continuing without it.', null);
|
||||
}
|
||||
}
|
||||
$progressMessage = $safeUpgradeRequested
|
||||
? 'Safe upgrade temporarily using legacy installer...'
|
||||
: 'Running legacy installer...';
|
||||
@@ -355,6 +382,172 @@ ERR;
|
||||
return false;
|
||||
}
|
||||
|
||||
private function captureCoreSnapshot(string $targetVersion): ?array
|
||||
{
|
||||
$entries = $this->collectSnapshotEntries();
|
||||
if (!$entries) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snapshotRoot = $this->resolveSnapshotStore();
|
||||
if (!$snapshotRoot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snapshotId = 'snapshot-' . date('YmdHis');
|
||||
$snapshotPath = $snapshotRoot . '/' . $snapshotId;
|
||||
try {
|
||||
Folder::create($snapshotPath);
|
||||
} catch (\Throwable $e) {
|
||||
error_log('[Grav Upgrade] Unable to create snapshot directory: ' . $e->getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$total = count($entries);
|
||||
foreach ($entries as $index => $entry) {
|
||||
$percent = $total > 0 ? (int)floor((($index + 1) / $total) * 100) : null;
|
||||
$this->relayProgress('snapshot', sprintf('Snapshotting %s (%d/%d)', $entry, $index + 1, $total), $percent);
|
||||
|
||||
$source = GRAV_ROOT . '/' . $entry;
|
||||
$destination = $snapshotPath . '/' . $entry;
|
||||
|
||||
try {
|
||||
$this->snapshotCopyEntry($source, $destination);
|
||||
} catch (\Throwable $e) {
|
||||
error_log('[Grav Upgrade] Snapshot copy failed for ' . $entry . ': ' . $e->getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$manifest = [
|
||||
'id' => $snapshotId,
|
||||
'created_at' => time(),
|
||||
'source_version' => GRAV_VERSION,
|
||||
'target_version' => $targetVersion,
|
||||
'php_version' => PHP_VERSION,
|
||||
'entries' => $entries,
|
||||
'package_path' => null,
|
||||
'backup_path' => $snapshotPath,
|
||||
'operation' => 'upgrade',
|
||||
'mode' => 'pre-upgrade',
|
||||
];
|
||||
|
||||
$this->persistSnapshotManifest($manifest);
|
||||
$this->lastManifest = $manifest;
|
||||
|
||||
return $manifest;
|
||||
}
|
||||
|
||||
private function collectSnapshotEntries(): array
|
||||
{
|
||||
$ignores = array_fill_keys($this->ignores, true);
|
||||
$ignores['user'] = true;
|
||||
|
||||
$entries = [];
|
||||
try {
|
||||
$iterator = new \DirectoryIterator(GRAV_ROOT);
|
||||
foreach ($iterator as $item) {
|
||||
if ($item->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $item->getFilename();
|
||||
if (isset($ignores[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entries[] = $name;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
error_log('[Grav Upgrade] Unable to enumerate snapshot entries: ' . $e->getMessage());
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
sort($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
private function snapshotCopyEntry(string $source, string $destination): void
|
||||
{
|
||||
if (is_link($source)) {
|
||||
$linkTarget = readlink($source);
|
||||
Folder::create(dirname($destination));
|
||||
if (is_link($destination) || is_file($destination)) {
|
||||
@unlink($destination);
|
||||
}
|
||||
if ($linkTarget !== false) {
|
||||
@symlink($linkTarget, $destination);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_dir($source)) {
|
||||
Folder::rcopy($source, $destination);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Folder::create(dirname($destination));
|
||||
if (!@copy($source, $destination)) {
|
||||
throw new RuntimeException(sprintf('Failed to copy file %s during snapshot.', $source));
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveSnapshotStore(): ?string
|
||||
{
|
||||
$candidates = [];
|
||||
try {
|
||||
$grav = Grav::instance();
|
||||
if ($grav && isset($grav['locator'])) {
|
||||
$path = $grav['locator']->findResource('tmp://grav-snapshots', true, true);
|
||||
if ($path) {
|
||||
$candidates[] = $path;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// ignore locator issues
|
||||
}
|
||||
$candidates[] = GRAV_ROOT . '/tmp/grav-snapshots';
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if (!$candidate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Folder::create($candidate);
|
||||
} catch (\Throwable $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir($candidate) && is_writable($candidate)) {
|
||||
return rtrim($candidate, '\\/');
|
||||
}
|
||||
}
|
||||
|
||||
error_log('[Grav Upgrade] Unable to locate writable snapshot directory; skipping snapshot.');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function persistSnapshotManifest(array $manifest): void
|
||||
{
|
||||
$store = GRAV_ROOT . '/user/data/upgrades';
|
||||
|
||||
try {
|
||||
Folder::create($store);
|
||||
$path = $store . '/' . $manifest['id'] . '.json';
|
||||
@file_put_contents($path, json_encode($manifest, JSON_PRETTY_PRINT));
|
||||
} catch (\Throwable $e) {
|
||||
error_log('[Grav Upgrade] Unable to write snapshot manifest: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
|
||||
Reference in New Issue
Block a user