コード例 #1
0
        /// <inheritdoc/>
        public async Task <int> RunAsync()
        {
            // Remove the synchronization context
            await default(SynchronizationContextRemover);

            // Populate the class catalog (if we haven't already)
            _classCatalog.Populate();

            // Run bootstrapper configurators first
            Configurators.Configure <IConfigurableBootstrapper>(this);
            Configurators.Configure <IBootstrapper>(this);

            // Run the configuration configurator and get the configuration root
            SettingsConfigurationProvider settingsProvider          = new SettingsConfigurationProvider();
            IConfigurationBuilder         configurationBuilder      = new ConfigurationBuilder();
            ConfigurableConfiguration     configurableConfiguration = new ConfigurableConfiguration(configurationBuilder);

            Configurators.Configure(configurableConfiguration);
            configurationBuilder.Add(settingsProvider);
            IConfigurationRoot    configurationRoot     = configurationBuilder.Build();
            ConfigurationSettings configurationSettings = new ConfigurationSettings(settingsProvider, configurationRoot);

            // Create the service collection
            IServiceCollection serviceCollection = CreateServiceCollection() ?? new ServiceCollection();

            serviceCollection.TryAddSingleton <IConfigurableBootstrapper>(this);
            serviceCollection.TryAddSingleton <IBootstrapper>(this);
            serviceCollection.TryAddSingleton(_classCatalog);  // The class catalog is retrieved later for deferred logging once a service provider is built
            serviceCollection.TryAddSingleton <IConfiguration>(configurationRoot);

            // Run configurators on the service collection
            ConfigurableServices configurableServices = new ConfigurableServices(serviceCollection, configurationRoot);

            Configurators.Configure(configurableServices);

            // Add simple logging to make sure it's available in commands before the engine adds in,
            // but add it after the configurators have a chance to configure logging
            serviceCollection.AddLogging();

            // Create the stand-alone command line service container and register a few types needed for the CLI
            CommandServiceTypeRegistrar registrar = new CommandServiceTypeRegistrar();

            registrar.RegisterInstance(typeof(IConfigurationSettings), configurationSettings);
            registrar.RegisterInstance(typeof(IConfigurationRoot), configurationRoot);
            registrar.RegisterInstance(typeof(IServiceCollection), serviceCollection);
            registrar.RegisterInstance(typeof(IConfiguratorCollection), Configurators);
            registrar.RegisterInstance(typeof(IBootstrapper), this);

            // Create the command line parser and run the command
            ICommandApp app = _getCommandApp(registrar);

            app.Configure(commandConfigurator =>
            {
                commandConfigurator.ValidateExamples();
                ConfigurableCommands configurableCommands = new ConfigurableCommands(commandConfigurator);
                Configurators.Configure(configurableCommands);
            });
            int exitCode = await app.RunAsync(Arguments);

            // Dispose all instances of the console logger to flush the message queue and stop the listening thread
            ConsoleLoggerProvider.DisposeAll();

            return(exitCode);
        }
コード例 #2
0
        protected override async Task <int> ExecuteEngineAsync(
            CommandContext commandContext,
            PreviewCommandSettings commandSettings,
            IEngineManager 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

            // 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
                    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);
        }
コード例 #3
0
        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);
        }