<commit_before>﻿using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Threading.Tasks;
using Hakudu.Bootstrapper.LocalStorage;

namespace Hakudu.Bootstrapper.Engine
{
    public class EngineHost
    {
        const string ENV_BOOTSTRAPPER_EXE = "HAKUDU_BOOTSTRAPPER_EXE";
        const string ENV_BOOTSTRAPPER_VERSION = "HAKUDU_BOOTSTRAPPER_VERSION";

        readonly BootstrapperContext _bootstrapper;

        public EngineHost(BootstrapperContext bootstrapper)
        {
            if (bootstrapper == null)
                throw new ArgumentNullException(nameof(bootstrapper));

            _bootstrapper = bootstrapper;
        }

        public async Task<int> StartAsync(EngineInfo engine)
        {
            if (engine == null)
                throw new ArgumentNullException(nameof(engine));

            var startInfo = new ProcessStartInfo(engine.ExePath)
            {
                WorkingDirectory = engine.InstallDir.FullName,
                UseShellExecute = false
            };

            SetEnvironmentVariables(startInfo.EnvironmentVariables);

            return await StartProcessAsync(startInfo);
        }

        void SetEnvironmentVariables(StringDictionary env)
        {
            env[ENV_BOOTSTRAPPER_EXE] = _bootstrapper.ExePath;
            env[ENV_BOOTSTRAPPER_VERSION] = _bootstrapper.Version.ToString();
        }

        static Task<int> StartProcessAsync(ProcessStartInfo startInfo)
        {
            var tcs = new TaskCompletionSource<int>();

            var process = new Process
            {
                StartInfo = startInfo,
                EnableRaisingEvents = true
            };

            process.Exited += (sender, e) =>
            {
                tcs.SetResult(process.ExitCode);
                process.Dispose();
            };

            try
            {
                if (!process.Start())
                {
                    var errorMessage = $"Failed to start the Hakudu engine process ({startInfo.FileName}).";
                    tcs.SetException(new EngineExecutionException(errorMessage));
                }
            }
            catch (Exception ex)
            {
                var errorMessage = $"Failed to start the Hakudu engine process ({startInfo.FileName}). {ex.Message}";
                tcs.SetException(new EngineExecutionException(errorMessage));
            }<commit_msg>EngineHost fix to preserve inner exception on failure<commit_after>﻿using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Threading.Tasks;
using Hakudu.Bootstrapper.LocalStorage;

namespace Hakudu.Bootstrapper.Engine
{
    public class EngineHost
    {
        const string ENV_BOOTSTRAPPER_EXE = "HAKUDU_BOOTSTRAPPER_EXE";
        const string ENV_BOOTSTRAPPER_VERSION = "HAKUDU_BOOTSTRAPPER_VERSION";

        readonly BootstrapperContext _bootstrapper;

        public EngineHost(BootstrapperContext bootstrapper)
        {
            if (bootstrapper == null)
                throw new ArgumentNullException(nameof(bootstrapper));

            _bootstrapper = bootstrapper;
        }

        public async Task<int> StartAsync(EngineInfo engine)
        {
            if (engine == null)
                throw new ArgumentNullException(nameof(engine));

            var startInfo = new ProcessStartInfo(engine.ExePath)
            {
                WorkingDirectory = engine.InstallDir.FullName,
                UseShellExecute = false
            };

            SetEnvironmentVariables(startInfo.EnvironmentVariables);

            return await StartProcessAsync(startInfo);
        }

        void SetEnvironmentVariables(StringDictionary env)
        {
            env[ENV_BOOTSTRAPPER_EXE] = _bootstrapper.ExePath;
            env[ENV_BOOTSTRAPPER_VERSION] = _bootstrapper.Version.ToString();
        }

        static Task<int> StartProcessAsync(ProcessStartInfo startInfo)
        {
            var tcs = new TaskCompletionSource<int>();

            var process = new Process
            {
                StartInfo = startInfo,
                EnableRaisingEvents = true
            };

            process.Exited += (sender, e) =>
            {
                tcs.SetResult(process.ExitCode);
                process.Dispose();
            };

            try
            {
                if (!process.Start())
                {
                    var errorMessage = $"Failed to start the Hakudu engine process ({startInfo.FileName}).";
                    tcs.SetException(new EngineExecutionException(errorMessage));
                }
            }
            catch (Exception ex)
            {
                var errorMessage = $"Failed to start the Hakudu engine process ({startInfo.FileName}). {ex.Message}";
                tcs.SetException(new EngineExecutionException(errorMessage, ex));
            }
{'fraction_non_alphanumeric': 0.0754909983633388, 'fraction_numerical': 0.0, 'mean_word_length': 1.8877731836975782, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, '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': '1359938', 'n_tokens_mistral': 1253, 'n_tokens_neox': 1211, 'n_words': 246}