Fassung 1.7.0: verlässliche Installation, übersichtliche Verwaltung und bedienbare Bewegung
This commit is contained in:
1 parent
b164c4edfe
commit
495b26896e
55 files changed
+1632
-423
No files matched your search
+54
-5
@@ -19,6 +19,8 @@ use Doctrine\DBAL\Connection;
|
||||
*/
|
||||
final class Updater
|
||||
{
|
||||
private array $environmentBefore = [];
|
||||
private ?string $backupDirectory = null;
|
||||
public const MAINTENANCE_FILE = 'var/maintenance';
|
||||
public const LOG_FILE = 'var/updates.log';
|
||||
|
||||
@@ -231,8 +233,22 @@ final class Updater
|
||||
$step($steps, 'Wartungszustand', true, 'Die Website antwortet mit 503, die Verwaltung bleibt erreichbar.');
|
||||
|
||||
$migrated = false;
|
||||
foreach (['.env', '.env.local'] as $file) {
|
||||
if (is_file($this->root.'/'.$file)) {
|
||||
$this->environmentBefore[$file] = (string) file_get_contents($this->root.'/'.$file);
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Older repositories tracked this file. Snapshot above, clear legacy index flags,
|
||||
// then let Git replace its own copy; restore the installation before booting PHP.
|
||||
if ($this->git(['ls-files', '--error-unmatch', '.env'])['ok']) {
|
||||
$this->git(['update-index', '--no-assume-unchanged', '--no-skip-worktree', '.env']);
|
||||
if (!$this->git(['checkout', '--', '.env'])['ok']) {
|
||||
throw new \RuntimeException('Die alte Git-Konfiguration konnte nicht für den Updatewechsel vorbereitet werden.');
|
||||
}
|
||||
}
|
||||
$checkout = $this->git(['checkout', '--force', $target]);
|
||||
$this->restoreEnvironment();
|
||||
if (!$step($steps, 'Code wechseln', $checkout['ok'], $checkout['ok'] ? 'Auf '.$target.' gewechselt.' : $checkout['output'])) {
|
||||
throw new \RuntimeException('checkout');
|
||||
}
|
||||
@@ -320,15 +336,27 @@ final class Updater
|
||||
private function rollback(array &$steps, string $commit, ?string $backup, callable $step): void
|
||||
{
|
||||
$back = $this->git(['checkout', '--force', $commit]);
|
||||
try {
|
||||
$this->restoreEnvironment();
|
||||
} catch (\RuntimeException $e) {
|
||||
$step($steps, 'Konfiguration wiederherstellen', false, $e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
$step($steps, 'Zurück auf den alten Stand', $back['ok'], $back['ok'] ? 'Auf '.substr($commit, 0, 8).' zurückgesetzt.' : $back['output']);
|
||||
|
||||
if (null !== $backup && null !== $this->databaseFile()) {
|
||||
$file = $this->databaseFile();
|
||||
$copy = dirname($backup).'/'.basename((string) $file);
|
||||
$copy = $this->backupDirectory.'/'.basename((string) $file);
|
||||
$restored = is_readable($copy) && @copy($copy, (string) $file);
|
||||
$step($steps, 'Datenbank zurückschreiben', $restored, $restored
|
||||
? 'Die Sicherung von vor der Migration ist wieder eingespielt.'
|
||||
: 'Die Sicherung ließ sich nicht zurückschreiben. Die Datenbank liegt unter '.dirname((string) $backup).'.');
|
||||
: 'Die Sicherung ließ sich nicht zurückschreiben. Die Datenbank liegt unter '.$this->backupDirectory.'.');
|
||||
if (!$restored) {
|
||||
$step($steps, 'Wartungszustand bleibt', false, 'Die Datenbank konnte nicht wiederhergestellt werden. Der Betrieb bleibt angehalten.');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$composer = $this->runner->resolve('composer', $this->root);
|
||||
@@ -346,11 +374,27 @@ final class Updater
|
||||
$step($steps, 'Wartungszustand bleibt', false, 'Auch der alte Stand antwortet nicht. Die Website bleibt im Wartungszustand, damit niemand eine kaputte Seite sieht. Ausgabe: '.$this->lastLine($health['output']));
|
||||
}
|
||||
|
||||
/** Legacy tags tracked .env; preserve the installation even when checking out those tags. */
|
||||
private function restoreEnvironment(): void
|
||||
{
|
||||
foreach ($this->environmentBefore as $file => $content) {
|
||||
$path = $this->root.'/'.$file;
|
||||
if (is_file($path) && file_get_contents($path) === $content) {
|
||||
continue;
|
||||
}
|
||||
if (false === @file_put_contents($path, $content, LOCK_EX)) {
|
||||
throw new \RuntimeException('Die Installationskonfiguration konnte nicht wiederhergestellt werden. Sie liegt in der Updatesicherung unter var/backups.');
|
||||
}
|
||||
@chmod($path, 0o600);
|
||||
}
|
||||
}
|
||||
|
||||
/** Copies the database and the environment files, and returns a sentence about it. */
|
||||
private function backup(): ?string
|
||||
{
|
||||
$directory = $this->root.'/var/backups/update-'.gmdate('Ymd-His');
|
||||
if (!is_dir($directory) && !@mkdir($directory, 0o775, true)) {
|
||||
$this->backupDirectory = null;
|
||||
$directory = $this->root.'/var/backups/update-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(4));
|
||||
if (!@mkdir($directory, 0o700, true)) {
|
||||
return null;
|
||||
}
|
||||
$file = $this->databaseFile();
|
||||
@@ -361,10 +405,15 @@ final class Updater
|
||||
}
|
||||
foreach (['.env', '.env.local'] as $environment) {
|
||||
if (is_readable($this->root.'/'.$environment)) {
|
||||
@copy($this->root.'/'.$environment, $directory.'/'.$environment);
|
||||
if (!@copy($this->root.'/'.$environment, $directory.'/'.$environment)) {
|
||||
return null;
|
||||
}
|
||||
@chmod($directory.'/'.$environment, 0o600);
|
||||
}
|
||||
}
|
||||
|
||||
$this->backupDirectory = $directory;
|
||||
|
||||
return sprintf(
|
||||
'%s (%s). Der Medienordner ist nicht dabei – er ist zu groß, und kein Update schreibt darin.',
|
||||
str_replace('\\', '/', substr($directory, strlen($this->root) + 1)),
|
||||
|
||||
Reference in new issue
Block a user