feat: add fnOS packaging, storage workflows and release pipeline
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace dy.net.service
|
||||
{
|
||||
public sealed class DatabaseUpgradeBackup
|
||||
{
|
||||
private readonly string _databaseRoot;
|
||||
private readonly string _version;
|
||||
private readonly string _markerPath;
|
||||
|
||||
private DatabaseUpgradeBackup(string databaseRoot, string version)
|
||||
{
|
||||
_databaseRoot = databaseRoot;
|
||||
_version = version;
|
||||
_markerPath = Path.Combine(databaseRoot, ".schema-version");
|
||||
}
|
||||
|
||||
public static DatabaseUpgradeBackup Prepare(string dbPath)
|
||||
{
|
||||
var root = string.IsNullOrWhiteSpace(dbPath)
|
||||
? Path.Combine(Environment.CurrentDirectory, "db")
|
||||
: Path.Combine(dbPath, "db");
|
||||
Directory.CreateDirectory(root);
|
||||
var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? "0.2.24";
|
||||
var backup = new DatabaseUpgradeBackup(root, version);
|
||||
backup.CreateIfNeeded();
|
||||
return backup;
|
||||
}
|
||||
|
||||
public void MarkSchemaReady() => File.WriteAllText(_markerPath, _version);
|
||||
|
||||
private void CreateIfNeeded()
|
||||
{
|
||||
var database = Path.Combine(_databaseRoot, "dy.sqlite");
|
||||
if (!File.Exists(database)) return;
|
||||
if (File.Exists(_markerPath) && string.Equals(File.ReadAllText(_markerPath).Trim(), _version, StringComparison.Ordinal)) return;
|
||||
|
||||
var backupRoot = Path.Combine(_databaseRoot, "upgrade-backups");
|
||||
Directory.CreateDirectory(backupRoot);
|
||||
var versionPrefix = $"pre-{_version}-";
|
||||
if (!Directory.EnumerateDirectories(backupRoot, versionPrefix + "*").Any())
|
||||
{
|
||||
var destination = Path.Combine(backupRoot, versionPrefix + DateTime.Now.ToString("yyyyMMdd-HHmmss"));
|
||||
Directory.CreateDirectory(destination);
|
||||
CopyIfPresent(database, Path.Combine(destination, "dy.sqlite"));
|
||||
CopyIfPresent(database + "-wal", Path.Combine(destination, "dy.sqlite-wal"));
|
||||
CopyIfPresent(database + "-shm", Path.Combine(destination, "dy.sqlite-shm"));
|
||||
CopyDirectory(Path.Combine(_databaseRoot, "keys"), Path.Combine(destination, "keys"));
|
||||
}
|
||||
|
||||
foreach (var old in new DirectoryInfo(backupRoot).GetDirectories()
|
||||
.OrderByDescending(x => x.CreationTimeUtc).Skip(3))
|
||||
{
|
||||
try { old.Delete(true); }
|
||||
catch (Exception ex) { Serilog.Log.Warning(ex, "清理旧升级备份失败:{Path}", old.FullName); }
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyIfPresent(string source, string destination)
|
||||
{
|
||||
if (File.Exists(source)) File.Copy(source, destination, false);
|
||||
}
|
||||
|
||||
private static void CopyDirectory(string source, string destination)
|
||||
{
|
||||
if (!Directory.Exists(source)) return;
|
||||
Directory.CreateDirectory(destination);
|
||||
foreach (var file in Directory.EnumerateFiles(source, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
var relative = Path.GetRelativePath(source, file);
|
||||
var target = Path.Combine(destination, relative);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(target)!);
|
||||
File.Copy(file, target, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user