public override sealed async Task <int> ExecuteCommandAsync(CommandContext commandContext, TSettings commandSettings) { // We need to get the engine command settings to pass to the engine manager // First try the actual command settings if (!(commandSettings is EngineCommandSettings engineCommandSettings)) { // Then try the command data or create one and either way copy over the base command settings engineCommandSettings = commandContext.Data as EngineCommandSettings ?? new EngineCommandSettings(); engineCommandSettings.LogLevel = commandSettings.LogLevel; engineCommandSettings.Attach = commandSettings.Attach; engineCommandSettings.LogFile = commandSettings.LogFile; } // Execute the engine manager and dispose it when done using (EngineManager engineManager = new EngineManager( commandContext, engineCommandSettings, EngineSettings, ConfigurationRoot, ServiceCollection, Bootstrapper)) { return(await ExecuteEngineAsync(commandContext, commandSettings, engineManager)); } }
public override async Task <int> ExecuteCommandAsync(IServiceCollection serviceCollection, CommandContext context, Settings settings) { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); using (EngineManager engineManager = new EngineManager(serviceCollection, _configurators, settings)) { return(await engineManager.ExecuteAsync(cancellationTokenSource) ? (int)ExitCode.Normal : (int)ExitCode.ExecutionError); } }
public override async Task <int> ExecuteCommandAsync(IServiceCollection serviceCollection, CommandContext context, Settings settings) { ExitCode exitCode = ExitCode.Normal; using (EngineManager engineManager = new EngineManager(serviceCollection, _configurators, settings)) { ILogger logger = engineManager.Engine.Services.GetRequiredService <ILogger <Bootstrapper> >(); // Execute the engine for the first time CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); if (!await engineManager.ExecuteAsync(cancellationTokenSource)) { return((int)ExitCode.ExecutionError); } // Start the preview server Dictionary <string, string> contentTypes = settings.ContentTypes?.Length > 0 ? GetContentTypes(settings.ContentTypes) : new Dictionary <string, string>(); ILoggerProvider loggerProvider = engineManager.Engine.Services.GetRequiredService <ILoggerProvider>(); Server previewServer = await StartPreviewServerAsync( engineManager.Engine.FileSystem.GetOutputDirectory().Path, settings.Port, settings.ForceExt, settings.VirtualDirectory, !settings.NoReload, contentTypes, loggerProvider, logger); // Start the watchers ActionFileSystemWatcher inputFolderWatcher = null; if (!settings.NoWatch) { logger.LogInformation("Watching paths(s) {0}", string.Join(", ", engineManager.Engine.FileSystem.InputPaths)); inputFolderWatcher = new ActionFileSystemWatcher( engineManager.Engine.FileSystem.GetOutputDirectory().Path, engineManager.Engine.FileSystem.GetInputDirectories().Select(x => x.Path), true, "*.*", path => { _changedFiles.Enqueue(path); _messageEvent.Set(); }); } // Start the message pump // Only wait for a key if console input has not been redirected, otherwise it's on the caller to exit if (!Console.IsInputRedirected) { // Start the key listening thread Thread thread = new Thread(() => { logger.LogInformation("Hit Ctrl-C to exit"); Console.TreatControlCAsInput = true; while (true) { // Would have preferred to use Console.CancelKeyPress, but that bubbles up to calling batch files // The (ConsoleKey)3 check is to support a bug in VS Code: https://github.com/Microsoft/vscode/issues/9347 ConsoleKeyInfo consoleKey = Console.ReadKey(true); if (consoleKey.Key == (ConsoleKey)3 || (consoleKey.Key == ConsoleKey.C && (consoleKey.Modifiers & ConsoleModifiers.Control) != 0)) { _exit.Set(); _messageEvent.Set(); break; } } }) { IsBackground = true }; thread.Start(); } // Wait for activity while (true) { _messageEvent.WaitOne(); // Blocks the current thread until a signal if (_exit) { break; } // Execute if files have changed HashSet <string> changedFiles = new HashSet <string>(); while (_changedFiles.TryDequeue(out string changedFile)) { if (changedFiles.Add(changedFile)) { logger.LogDebug($"{changedFile} has changed"); } } if (changedFiles.Count > 0) { logger.LogInformation($"{changedFiles.Count} files have changed, re-executing"); // Reset caches when an error occurs during the previous preview object existingResetCacheSetting = null; bool setResetCacheSetting = false; if (exitCode == ExitCode.ExecutionError) { existingResetCacheSetting = engineManager.Engine.Settings.GetValueOrDefault(Keys.ResetCache); setResetCacheSetting = true; engineManager.Engine.Settings[Keys.ResetCache] = true; } // If there was an execution error due to reload, keep previewing but clear the cache cancellationTokenSource = new CancellationTokenSource(); exitCode = await engineManager.ExecuteAsync(cancellationTokenSource) ? ExitCode.Normal : ExitCode.ExecutionError; // Reset the reset cache setting after removing it if (setResetCacheSetting) { if (existingResetCacheSetting == null) { engineManager.Engine.Settings.Remove(Keys.ResetCache); } { engineManager.Engine.Settings[Keys.ResetCache] = existingResetCacheSetting; } } await previewServer.TriggerReloadAsync(); } // Check one more time for exit if (_exit) { break; } logger.LogInformation("Hit Ctrl-C to exit"); _messageEvent.Reset(); } // Shutdown logger.LogInformation("Shutting down"); inputFolderWatcher?.Dispose(); previewServer.Dispose(); } return((int)exitCode); }