Добавьте файлы проекта.

This commit is contained in:
2025-11-25 07:39:25 +03:00
parent ed6a7e1938
commit 5bbcfb1e76
21 changed files with 793 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
namespace Updater.Core;
/// <summary>
/// Безопасный установщик: создает резервную копию замененных файлов, выполняет атомарную замену,
/// и откатываемся в случае неудачи.
/// </summary>
public sealed class SafeFileInstaller : IInstaller
{
private readonly ILogger _log;
public SafeFileInstaller(ILogger log) => _log = log;
public void Install(string sourceDir, string installPath)
{
var backupDir = Path.Combine(Path.GetTempPath(), $"upd_backup_{Guid.NewGuid():N}");
Directory.CreateDirectory(backupDir);
var completed = false;
try
{
// Копирование файлов с резервной копией целей
foreach (var src in Directory.EnumerateFiles(sourceDir, "*", SearchOption.AllDirectories))
{
var rel = Path.GetRelativePath(sourceDir, src);
var dst = Path.Combine(installPath, rel);
var dstDir = Path.GetDirectoryName(dst)!;
Directory.CreateDirectory(dstDir);
if (File.Exists(dst))
{
var bkp = Path.Combine(backupDir, rel);
Directory.CreateDirectory(Path.GetDirectoryName(bkp)!);
File.Copy(dst, bkp, overwrite: true);
}
File.Copy(src, dst, overwrite: true);
}
completed = true;
_log.Info("Install completed successfully.");
}
catch (Exception ex)
{
_log.Error($"Install failed: {ex.Message}");
_log.Warn("Rolling back...");
Rollback(backupDir, installPath);
throw;
}
finally
{
// Очистка резервной копии только в случае успеха
if (completed)
{
TryDeleteDirectory(backupDir);
}
}
}
private static void Rollback(string backupDir, string installPath)
{
if (!Directory.Exists(backupDir)) return;
foreach (var bkp in Directory.EnumerateFiles(backupDir, "*", SearchOption.AllDirectories))
{
var rel = Path.GetRelativePath(backupDir, bkp);
var dst = Path.Combine(installPath, rel);
Directory.CreateDirectory(Path.GetDirectoryName(dst)!);
File.Copy(bkp, dst, overwrite: true);
}
}
private static void TryDeleteDirectory(string dir)
{
try { Directory.Delete(dir, true); } catch { /* ignore */ }
}
}