Files
Archive/netch/Netch/Services/Updater.cs
2024-03-05 02:32:38 -08:00

135 lines
4.1 KiB
C#

using System.Collections.Immutable;
using System.Diagnostics;
using System.Text;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Services;
public class Updater
{
private string UpdateFile { get; }
private string InstallDirectory { get; }
private readonly string _tempDirectory;
private static readonly string[] KeepDirectories = { "data", "mode\\Custom", "logging" };
private static readonly string[] KeepFiles = { Constants.DisableModeDirectoryFileName };
internal Updater(string updateFile, string installDirectory)
{
UpdateFile = updateFile;
InstallDirectory = installDirectory;
_tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(_tempDirectory);
}
#region Apply Update
internal void ApplyUpdate()
{
var extractPath = Path.Combine(_tempDirectory, "extract");
int exitCode;
if ((exitCode = Extract(extractPath)) != 0)
throw new MessageException(i18N.Translate($"7za unexpectedly exited. ({exitCode})"));
// update archive file must have a top-level directory "Netch"
var updateDirectory = Path.Combine(extractPath, "Netch");
if (!Directory.Exists(updateDirectory))
throw new MessageException(i18N.Translate("Update file top-level directory not exist"));
// {_tempDirectory}/extract/Netch/Netch.exe
var updateMainProgramFilePath = Path.Combine(updateDirectory, "Netch.exe");
if (!File.Exists(updateMainProgramFilePath))
throw new MessageException(i18N.Translate($"Update file main program not exist"));
MarkFilesOld();
// move {tempDirectory}\extract\Netch to install folder
MoveFilesOver(updateDirectory, InstallDirectory);
}
private void MarkFilesOld()
{
var keepDirFullPath = KeepDirectories.Select(d => Path.Combine(InstallDirectory, d)).ToImmutableList();
foreach (var file in Directory.GetFiles(InstallDirectory, "*", SearchOption.AllDirectories))
{
if (keepDirFullPath.Any(p => file.StartsWith(p)))
continue;
if (KeepFiles.Contains(Path.GetFileName(file)))
continue;
try
{
File.Move(file, file + ".old");
}
catch (Exception e)
{
Log.Error(e, "failed to rename file \"{File}\"", file);
throw;
}
}
}
private int Extract(string destDirName)
{
// release 7za.exe to {tempDirectory}\7za.exe
var temp7za = Path.Combine(_tempDirectory, "7za.exe");
if (!File.Exists(temp7za))
File.WriteAllBytes(temp7za, Resources._7za);
var argument = new StringBuilder($" x \"{UpdateFile}\" -o\"{destDirName}\" -y");
var process = Process.Start(new ProcessStartInfo(temp7za, argument.ToString())
{
UseShellExecute = false
})!;
process.WaitForExit();
return process.ExitCode;
}
private static void MoveFilesOver(string source, string target)
{
foreach (string directory in Directory.GetDirectories(source))
{
string dirName = Path.GetFileName(directory);
if (!Directory.Exists(Path.Combine(target, dirName)))
Directory.CreateDirectory(Path.Combine(target, dirName));
MoveFilesOver(directory, Path.Combine(target, dirName));
}
foreach (string file in Directory.GetFiles(source))
{
var destFile = Path.Combine(target, Path.GetFileName(file));
File.Delete(destFile);
File.Move(file, destFile);
}
}
#endregion
#region Clean files marked as old when start
public static void CleanOld(string targetPath)
{
foreach (var f in Directory.GetFiles(targetPath, "*.old", SearchOption.AllDirectories))
try
{
File.Delete(f);
}
catch (Exception)
{
// ignored
}
}
#endregion
}