<commit_before>﻿using StorybrewEditor.Util;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;

namespace StorybrewEditor
{
    public static class Updater
    {
        private static string[] ignoredPaths = { ".vscode/", "cache/", "logs/", "settings.cfg" };

        public const string UpdateArchivePath = "cache/net/update";
        public const string UpdateFolderPath = "cache/update";

        public static void OpenLastestReleasePage()
            => Process.Start($"https://github.com/{Program.Repository}/releases/latest");

        public static void Update(string destinationFolder, Version fromVersion)
        {
            Trace.WriteLine($"Updating from version {fromVersion} to {Program.Version}");
            var updaterPath = Assembly.GetEntryAssembly().Location;
            var sourceFolder = Path.GetDirectoryName(updaterPath);
            try
            {
                replaceFiles(sourceFolder, destinationFolder, ignoredPaths);
            }
            catch (Exception e)
            {
                Trace.WriteLine($"Failed to replace files: {e}");
                MessageBox.Show($"Update failed, please update manually.\n\n{e}", Program.FullName);
                OpenLastestReleasePage();
                return;
            }

            // Start the updated process
            var relativeProcessPath = PathHelper.GetRelativePath(sourceFolder, updaterPath);
            var processPath = Path.Combine(destinationFolder, relativeProcessPath);

            Trace.WriteLine($"\nUpdate complete, starting {processPath}");
            Process.Start(processPath);
        }

        private static void replaceFiles(string sourceFolder, string destinationFolder, string[] ignorePaths)
        {
            Trace.WriteLine($"\nCopying files from {sourceFolder} to {destinationFolder}");
            foreach (var sourceFilename in Directory.GetFiles(sourceFolder, "*", SearchOption.AllDirectories))
            {
                var relativeFilename = PathHelper.GetRelativePath(sourceFolder, sourceFilename);

                var ignoreFile = false;
                foreach (var ignorePath in ignorePaths)
                {
                    if (relativeFilename.StartsWith(ignorePath))
                    {
                        Trace.WriteLine($"  Ignoring {relativeFilename}, matches {ignorePath}");
                        ignoreFile = true;
                        break;
                    }
                }
                if (ignoreFile) continue;

                var destinationFilename = Path.Combine(destinationFolder, relativeFilename);
                Trace.WriteLine($"  Copying {relativeFilename} to {destinationFilename}");
                replaceFile(sourceFilename, destinationFilename);
            }
        }

        private static void replaceFile(string sourceFilename, string destinationFilename, int timeout = 5000)
        {
            var attempts = 0;
            while (true)
            {
                try
                {
                    File.Copy(sourceFilename, destinationFilename, true);
                    return;
                }
                catch
                {
                    attempts++;
                    var delay = 200;
                    if (attempts * delay > timeout) throw;

                    Trace.WriteLine($"      Waiting for {destinationFilename} {attempts}/{timeout / delay}");
                    Thread.Sleep(delay);
                }
            }
        }
    }<commit_msg>Fix missing folders not being created when updating.<commit_after>﻿using StorybrewEditor.Util;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;

namespace StorybrewEditor
{
    public static class Updater
    {
        private static string[] ignoredPaths = { ".vscode/", "cache/", "logs/", "settings.cfg" };

        public const string UpdateArchivePath = "cache/net/update";
        public const string UpdateFolderPath = "cache/update";

        public static void OpenLastestReleasePage()
            => Process.Start($"https://github.com/{Program.Repository}/releases/latest");

        public static void Update(string destinationFolder, Version fromVersion)
        {
            Trace.WriteLine($"Updating from version {fromVersion} to {Program.Version}");
            var updaterPath = Assembly.GetEntryAssembly().Location;
            var sourceFolder = Path.GetDirectoryName(updaterPath);
            try
            {
                replaceFiles(sourceFolder, destinationFolder, ignoredPaths);
            }
            catch (Exception e)
            {
                Trace.WriteLine($"Failed to replace files: {e}");
                MessageBox.Show($"Update failed, please update manually.\n\n{e}", Program.FullName);
                OpenLastestReleasePage();
                return;
            }

            // Start the updated process
            var relativeProcessPath = PathHelper.GetRelativePath(sourceFolder, updaterPath);
            var processPath = Path.Combine(destinationFolder, relativeProcessPath);

            Trace.WriteLine($"\nUpdate complete, starting {processPath}");
            Process.Start(processPath);
        }

        private static void replaceFiles(string sourceFolder, string destinationFolder, string[] ignorePaths)
        {
            Trace.WriteLine($"\nCopying files from {sourceFolder} to {destinationFolder}");
            foreach (var sourceFilename in Directory.GetFiles(sourceFolder, "*", SearchOption.AllDirectories))
            {
                var relativeFilename = PathHelper.GetRelativePath(sourceFolder, sourceFilename);

                var ignoreFile = false;
                foreach (var ignorePath in ignorePaths)
                {
                    if (relativeFilename.StartsWith(ignorePath))
                    {
                        Trace.WriteLine($"  Ignoring {relativeFilename}, matches {ignorePath}");
                        ignoreFile = true;
                        break;
                    }
                }
                if (ignoreFile) continue;

                var destinationFilename = Path.Combine(destinationFolder, relativeFilename);
                Trace.WriteLine($"  Copying {relativeFilename} to {destinationFilename}");
                replaceFile(sourceFilename, destinationFilename);
            }
        }

        private static void replaceFile(string sourceFilename, string destinationFilename, int timeout = 5000)
        {
            var destinationFolder = Path.GetDirectoryName(destinationFilename);
            if (!Directory.Exists(destinationFolder))
                Directory.CreateDirectory(destinationFolder);

            var attempts = 0;
            while (true)
            {
                try
                {
                    File.Copy(sourceFilename, destinationFilename, true);
                    return;
                }
                catch
                {
                    attempts++;
                    var delay = 200;
                    if (attempts * delay > timeout) throw;

                    Trace.WriteLine($"      Waiting for {destinationFilename} {attempts}/{timeout / delay}");
                    Thread.Sleep(delay);
                }
            }
        }
    }
{'fraction_non_alphanumeric': 0.0874493927125506, 'fraction_numerical': 0.0021592442645074223, 'mean_word_length': 1.7944947209653093, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7011740', 'n_tokens_mistral': 1708, 'n_tokens_neox': 1598, 'n_words': 399}