Example #1
0
        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);
        }