6dadd272创建于 8月26日历史提交
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;

namespace PixiEditor.UpdateModule;

public class UpdateInstaller
{
    public const string TargetDirectoryName = "UpdateFiles";

    public UpdateInstaller(string archiveFileName, string targetDirectory)
    {
        ArchiveFileName = archiveFileName;
        TargetDirectory = targetDirectory;
    }

    public static string UpdateFilesPath { get; set; } =
        Path.Join(UpdateDownloader.DownloadLocation, TargetDirectoryName);

    public string ArchiveFileName { get; set; }

    public string TargetDirectory { get; set; }

    public void Install(StringBuilder log)
    {
        var processes = Process.GetProcessesByName("PixiEditor.Desktop");
        processes = processes.Concat(Process.GetProcessesByName("PixiEditor")).ToArray();
        log.AppendLine($"Found {processes.Length} PixiEditor processes running.");
        if (processes.Length > 0)
        {
            log.AppendLine("Killing PixiEditor processes...");
            foreach (var process in processes)
            {
                try
                {
                    log.AppendLine($"Killing process {process.ProcessName} with ID {process.Id}");
                    process.Kill();
                    process.WaitForExit();
                }
                catch (Exception ex)
                {
                    log.AppendLine($"Failed to kill process {process.ProcessName} with ID {process.Id}: {ex.Message}");
                }
            }

            log.AppendLine("Processes killed.");
        }

        log.AppendLine("Extracting files");

        if (Directory.Exists(UpdateFilesPath))
        {
            Directory.Delete(UpdateFilesPath, true);
        }

        Directory.CreateDirectory(UpdateFilesPath);

        log.AppendLine($"Extracting {ArchiveFileName} to {UpdateFilesPath}");
        ZipFile.ExtractToDirectory(ArchiveFileName, UpdateFilesPath, true);

        string[] extractedFiles = Directory.GetFiles(UpdateFilesPath, "*", SearchOption.AllDirectories);
        log.AppendLine($"Extracted {extractedFiles.Length} files to {UpdateFilesPath}");
        log.AppendLine("Files extracted");

        string dirWithFiles = UpdateFilesPath;
        string binName = "PixiEditor.exe";
        if (!File.Exists(Path.Combine(UpdateFilesPath, binName)))
        {
            dirWithFiles = Directory.GetDirectories(UpdateFilesPath)[0];
        }

        log.AppendLine($"Copying files from {dirWithFiles} to {TargetDirectory}");

        try
        {
            CopyFilesToDestination(dirWithFiles, log);
        }
        catch (IOException ex)
        {
            log.AppendLine($"Error copying files: {ex.Message}. Retrying in 1 second...");
            System.Threading.Thread.Sleep(1000);
            CopyFilesToDestination(dirWithFiles, log);
        }

        log.AppendLine("Files copied");
        log.AppendLine("Deleting archive and update files");

        Cleanup(log);
    }

    private void Cleanup(StringBuilder logger)
    {
        File.Delete(ArchiveFileName);
        Directory.Delete(UpdateFilesPath, true);
        string updateLocationFile = Path.Join(Path.GetTempPath(), "PixiEditor", "update-location.txt");
        logger.AppendLine($"Looking for: {updateLocationFile}");
        if (File.Exists(updateLocationFile))
        {
            try
            {
                logger.AppendLine($"Deleting update location file: {updateLocationFile}");
                File.Delete(updateLocationFile);
            }
            catch (Exception ex)
            {
                logger.AppendLine($"Failed to delete update location file: {ex.Message}");
            }
        }

        string updateInstallerFile = Path.Join(Path.GetTempPath(), "PixiEditor",
            "PixiEditor.UpdateInstaller.exe");
        logger.AppendLine($"Looking for: {updateInstallerFile}");
        if (File.Exists(updateInstallerFile))
        {
            try
            {
                logger.AppendLine($"Deleting update installer file: {updateInstallerFile}");
                File.Delete(updateInstallerFile);
            }
            catch (Exception ex)
            {
                logger.AppendLine($"Failed to delete update installer file: {ex.Message}");
            }
        }
    }

    private void CopyFilesToDestination(string sourceDirectory, StringBuilder log)
    {
        int totalFiles = Directory.GetFiles(UpdateFilesPath, "*", SearchOption.AllDirectories).Length;
        log.AppendLine($"Found {totalFiles} files to copy.");

        string[] files = Directory.GetFiles(sourceDirectory);

        foreach (string file in files)
        {
            string targetFileName = Path.GetFileName(file);
            string targetFilePath = Path.Join(TargetDirectory, targetFileName);
            log.AppendLine($"Copying {file} to {targetFilePath}");
            File.Copy(file, targetFilePath, true);
        }

        CopySubDirectories(sourceDirectory, TargetDirectory, log);
    }

    private void CopySubDirectories(string originDirectory, string targetDirectory, StringBuilder log)
    {
        string[] subDirs = Directory.GetDirectories(originDirectory);
        log.AppendLine($"Found {subDirs.Length} subdirectories to copy.");
        if (subDirs.Length == 0) return;

        foreach (string subDir in subDirs)
        {
            string targetDirPath = Path.Join(targetDirectory, Path.GetFileName(subDir));

            log.AppendLine($"Copying {subDir} to {targetDirPath}");

            CopySubDirectories(subDir, targetDirPath, log);

            string[] files = Directory.GetFiles(subDir);

            if (!Directory.Exists(targetDirPath))
            {
                Directory.CreateDirectory(targetDirPath);
            }

            foreach (string file in files)
            {
                string targetFileName = Path.GetFileName(file);
                log.AppendLine($"Copying {file} to {Path.Join(targetDirPath, targetFileName)}");
                File.Copy(file, Path.Join(targetDirPath, targetFileName), true);
            }
        }
    }
}