protected override async Task <int> ExecuteEngineAsync( CommandContext commandContext, ServeCommandSettings commandSettings, IEngineManager engineManager) { ExitCode exitCode = ExitCode.Normal; ILogger logger = engineManager.Engine.Services.GetRequiredService <ILogger <Bootstrapper> >(); // Set folders IFileSystem fileSystem = engineManager.Engine.FileSystem; NormalizedPath currentDirectory = Environment.CurrentDirectory; IDirectory serveDirectory; if (string.IsNullOrEmpty(commandSettings.RootPath)) { fileSystem.RootPath = currentDirectory; serveDirectory = fileSystem.GetOutputDirectory(); } else { fileSystem.RootPath = currentDirectory.Combine(commandSettings.RootPath); serveDirectory = fileSystem.GetRootDirectory(); } Dictionary <string, string> contentTypes = commandSettings.ContentTypes?.Length > 0 ? PreviewCommand.GetContentTypes(commandSettings.ContentTypes) : new Dictionary <string, string>(); ILoggerProvider loggerProvider = engineManager.Engine.Services.GetRequiredService <ILoggerProvider>(); Server previewServer = null; FileSystemWatcher serveFolderWatcher = null; if (serveDirectory.Exists) { // Starts Preview server previewServer = await PreviewCommand.StartPreviewServerAsync( serveDirectory.Path, commandSettings.Port, commandSettings.ForceExt, commandSettings.VirtualDirectory, !commandSettings.NoReload, contentTypes, loggerProvider, logger); // Start the watchers if (!commandSettings.NoReload) { logger.LogInformation("Watching path {0}", serveDirectory.Path); serveFolderWatcher = new FileSystemWatcher(serveDirectory.Path.FullPath, "*.*") { IncludeSubdirectories = true, EnableRaisingEvents = true }; serveFolderWatcher.Changed += OnFileChanged; serveFolderWatcher.Created += OnFileChanged; } // Start the message pump CommandUtilities.WaitForControlC( () => { _exit.Set(); _messageEvent.Set(); }, logger); // 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-loading"); await previewServer.TriggerReloadAsync(); } // Check one more time for exit if (_exit) { break; } logger.LogInformation("Hit Ctrl-C to exit"); _messageEvent.Reset(); } } else { logger.LogError($"Directory {serveDirectory.Path} does not exist."); } // Shutdown logger.LogInformation("Shutting down"); if (serveFolderWatcher != null) { serveFolderWatcher.EnableRaisingEvents = false; serveFolderWatcher.Changed -= OnFileChanged; serveFolderWatcher.Created -= OnFileChanged; serveFolderWatcher.Dispose(); } previewServer?.Dispose(); return((int)exitCode); }
protected override async Task <int> ExecuteEngineAsync( CommandContext commandContext, PreviewCommandSettings commandSettings, IEngineManager engineManager) { SetPipelines(commandContext, commandSettings, engineManager); ExitCode exitCode = ExitCode.Normal; ILogger logger = engineManager.Engine.Services.GetRequiredService <ILogger <Bootstrapper> >(); // Execute the engine for the first time using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource()) { if (!await engineManager.ExecuteAsync(cancellationTokenSource)) { return((int)ExitCode.ExecutionError); } } // Start the preview server Dictionary <string, string> contentTypes = commandSettings.ContentTypes?.Length > 0 ? GetContentTypes(commandSettings.ContentTypes) : new Dictionary <string, string>(); ILoggerProvider loggerProvider = engineManager.Engine.Services.GetRequiredService <ILoggerProvider>(); IDirectory outputDirectory = engineManager.Engine.FileSystem.GetOutputDirectory(); Server previewServer = null; if (outputDirectory.Exists) { previewServer = await StartPreviewServerAsync( outputDirectory.Path, commandSettings.Port, commandSettings.ForceExt, commandSettings.VirtualDirectory, !commandSettings.NoReload, contentTypes, loggerProvider, logger); } // Start the watchers ActionFileSystemWatcher inputFolderWatcher = null; if (!commandSettings.NoWatch) { logger.LogInformation("Watching paths(s) {0}", string.Join(", ", engineManager.Engine.FileSystem.InputPaths)); inputFolderWatcher = new ActionFileSystemWatcher( outputDirectory.Path, engineManager.Engine.FileSystem.GetInputDirectories().Select(x => x.Path), true, "*.*", path => { _changedFiles.Enqueue(path); _messageEvent.Set(); }); } // Start the message pump CommandUtilities.WaitForControlC( () => { _exit.Set(); _messageEvent.Set(); }, logger); // 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 string existingResetCacheSetting = null; bool setResetCacheSetting = false; if (exitCode == ExitCode.ExecutionError) { existingResetCacheSetting = engineManager.Engine.Settings.GetString(Keys.ResetCache); setResetCacheSetting = true; ConfigurationSettings[Keys.ResetCache] = "true"; } // If there was an execution error due to reload, keep previewing but clear the cache using (CancellationTokenSource 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) { ConfigurationSettings.Remove(Keys.ResetCache); } { ConfigurationSettings[Keys.ResetCache] = existingResetCacheSetting; } } if (previewServer == null) { if (outputDirectory.Exists) { previewServer = await StartPreviewServerAsync( outputDirectory.Path, commandSettings.Port, commandSettings.ForceExt, commandSettings.VirtualDirectory, !commandSettings.NoReload, contentTypes, loggerProvider, logger); } } else { 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); }