private void Evaluate(string code, FilePath configFilePath) { if (string.IsNullOrEmpty(code)) { return; } Stopwatch stopwatch = Stopwatch.StartNew(); using (Trace.WithIndent().Information("Evaluating configuration script")) { CacheManager cacheManager = new CacheManager( _engine, _scriptManager, configFilePath?.AppendExtension(".dll"), configFilePath?.AppendExtension(".hash"), configFilePath?.AppendExtension(".generated.cs")); cacheManager.EvaluateCode(code, ClassCatalog.GetClasses <IModule>().ToList(), OutputScript, IgnoreConfigHash, NoOutputConfigAssembly); stopwatch.Stop(); Trace.Information($"Evaluated configuration script in {stopwatch.ElapsedMilliseconds} ms"); } }
/// <inheritdoc /> public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context) { HtmlParser parser = new HtmlParser(); using (IJsEnginePool enginePool = context.GetJsEnginePool(x => { if (string.IsNullOrWhiteSpace(_highlightJsFile)) { x.ExecuteResource("highlight-all.js", typeof(Highlight)); } else { x.ExecuteFile(_highlightJsFile); } })) { return(inputs.AsParallel().Select(context, input => { // We materialize the list before exiting the using statement, so safe to access enginePool // ReSharper disable once AccessToDisposedClosure using (IJsEngine engine = enginePool.GetEngine()) { try { using (Stream stream = input.GetStream()) using (IHtmlDocument htmlDocument = parser.Parse(stream)) { foreach (AngleSharp.Dom.IElement element in htmlDocument.QuerySelectorAll(_codeQuerySelector)) { // Don't highlight anything that potentially is already highlighted if (element.ClassList.Contains("hljs")) { continue; } // Make sure to use TextContent, otherwise you'll get escaped html which highlight.js won't parse engine.SetVariableValue("input", element.TextContent); // Check if they specified a language in their code block string language = element.ClassList.FirstOrDefault(i => i.StartsWith("language")); try { if (language != null) { engine.SetVariableValue("language", language.Replace("language-", "")); engine.Execute("result = hljs.highlight(language, input)"); } else { language = "(auto)"; // set this to auto in case there is an exception below engine.Execute("result = hljs.highlightAuto(input)"); string detectedLanguage = engine.Evaluate <string>("result.language"); if (string.IsNullOrWhiteSpace(detectedLanguage) == false) { element.ClassList.Add("language-" + detectedLanguage); } } element.ClassList.Add("hljs"); string formatted = engine.Evaluate <string>("result.value"); element.InnerHtml = formatted; } catch (Exception innerEx) { if (innerEx.Message.Contains("Unknown language: ") && _warnOnMissingLanguage) { Trace.Warning("Exception while highlighting source code for {0} using language {1}: {2}", input.SourceString(), language, innerEx.Message); } else { Trace.Information("Exception while highlighting source code for {0} using language {1}: {2}", input.SourceString(), language, innerEx.Message); } } } string content = htmlDocument.ToHtml(); return context.GetDocument(input, content); } } catch (Exception ex) { Trace.Warning("Exception while highlighting source code for {0}: {1}", input.SourceString(), ex.Message); return input; } } }).ToList()); } }
internal void InstallPackages(FilePath configFilePath) { DirectoryPath packagesPath = GetAbsolutePackagesPath(); Trace.Information($"Installing packages to {packagesPath.FullPath} (using {(UseLocalPackagesFolder ? "local" : "global")} packages folder)"); try { // Add the global default sources if requested if (UseGlobalPackageSources) { _sourceRepositories.AddGlobalDefaults(); } // Add the default package sources if (!IgnoreDefaultSources) { _sourceRepositories.AddDefaultPackageSources(); } // Get the local repository SourceRepository localRepository = _sourceRepositories.CreateRepository(packagesPath.FullPath); // Cache the packages in a packages file FilePath packagesFilePath = configFilePath?.AppendExtension(".packages.xml"); if (packagesFilePath == null) { Trace.Verbose("Will not write packages file since no config file was provided"); } else { Trace.Verbose($"Writing packages file to {packagesFilePath.FullPath}"); } using (InstalledPackagesCache installedPackages = new InstalledPackagesCache(packagesFilePath, UpdatePackages)) { // Get the package manager and repositories WyamFolderNuGetProject nuGetProject = new WyamFolderNuGetProject(_fileSystem, _assemblyLoader, _currentFramework, installedPackages, packagesPath.FullPath); NuGetPackageManager packageManager = new NuGetPackageManager(_sourceRepositories, _settings, packagesPath.FullPath) { PackagesFolderNuGetProject = nuGetProject }; IReadOnlyList <SourceRepository> remoteRepositories = _sourceRepositories.GetDefaultRepositories(); // Resolve all the versions IReadOnlyList <SourceRepository> installationRepositories = remoteRepositories; try { ResolveVersions(localRepository, remoteRepositories); } catch (Exception ex) { Trace.Verbose($"Exception while resolving package versions: {ex.Message}"); Trace.Warning("Error while resolving package versions, attempting without remote repositories"); installationRepositories = new[] { localRepository }; ResolveVersions(localRepository, Array.Empty <SourceRepository>()); } // Install the packages (doing this synchronously since doing it in parallel triggers file lock errors in NuGet on a clean system) try { InstallPackages(packageManager, installationRepositories, installedPackages); } catch (Exception ex) { Trace.Verbose($"Exception while installing packages: {(ex is AggregateException aex ? aex.Flatten() : ex)}"); Trace.Warning("Error while installing packages, attempting without remote repositories"); InstallPackages(packageManager, Array.Empty <SourceRepository>(), installedPackages); } // Process the package (do this after all packages have been installed) nuGetProject.ProcessAssembliesAndContent(); } } catch (Exception ex) { Trace.Verbose($"Unexpected exception while installing packages: {(ex is AggregateException ? string.Join("; ", ((AggregateException)ex).InnerExceptions.Select(x => x.Message)) : ex.Message)}"); Trace.Warning("Error while installing packages, attempting to continue anyway"); } }
public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context) { // Register all the MVC and Razor services // In the future, if DI is implemented for all Wyam, the IExecutionContext would be registered as a service // and the IHostingEnviornment would be registered as transient with the execution context provided in ctor IServiceCollection serviceCollection = new ServiceCollection(); IMvcCoreBuilder builder = serviceCollection .AddMvcCore() .AddRazorViewEngine(); builder.PartManager.FeatureProviders.Add(new MetadataReferenceFeatureProvider(context)); serviceCollection.Configure <RazorViewEngineOptions>(options => { options.ViewLocationExpanders.Add(new ViewLocationExpander()); }); serviceCollection .AddSingleton <ILoggerFactory, TraceLoggerFactory>() .AddSingleton <DiagnosticSource, SilentDiagnosticSource>() .AddSingleton <IHostingEnvironment, HostingEnvironment>() .AddSingleton <ObjectPoolProvider, DefaultObjectPoolProvider>() .AddSingleton <IExecutionContext>(context) .AddSingleton <IBasePageTypeProvider>(new BasePageTypeProvider(_basePageType ?? typeof(WyamRazorPage <>))) .AddScoped <IMvcRazorHost, RazorHost>(); IServiceProvider services = serviceCollection.BuildServiceProvider(); // Eliminate input documents that we shouldn't process List <IDocument> validInputs = inputs .Where(x => _ignorePrefix == null || !x.ContainsKey(Keys.SourceFileName) || !x.FilePath(Keys.SourceFileName).FullPath.StartsWith(_ignorePrefix)) .ToList(); if (validInputs.Count < inputs.Count) { Trace.Information($"Ignoring {inputs.Count - validInputs.Count} inputs due to source file name prefix"); } // Compile and evaluate the pages in parallel IServiceScopeFactory scopeFactory = services.GetRequiredService <IServiceScopeFactory>(); return(validInputs.AsParallel().Select(input => { Trace.Verbose("Processing Razor for {0}", input.SourceString()); using (var scope = scopeFactory.CreateScope()) { // Get services IRazorViewEngine viewEngine = scope.ServiceProvider.GetRequiredService <IRazorViewEngine>(); IRazorPageActivator pageActivator = scope.ServiceProvider.GetRequiredService <IRazorPageActivator>(); HtmlEncoder htmlEncoder = scope.ServiceProvider.GetRequiredService <HtmlEncoder>(); IRazorPageFactoryProvider pageFactoryProvider = scope.ServiceProvider.GetRequiredService <IRazorPageFactoryProvider>(); IRazorCompilationService razorCompilationService = scope.ServiceProvider.GetRequiredService <IRazorCompilationService>(); IHostingEnvironment hostingEnviornment = scope.ServiceProvider.GetRequiredService <IHostingEnvironment>(); // Compile the view string relativePath = GetRelativePath(input, context); FilePath viewStartLocationPath = _viewStartPath?.Invoke <FilePath>(input, context); string viewStartLocation = viewStartLocationPath != null ? GetRelativePath(viewStartLocationPath, context) : null; string layoutLocation = _layoutPath?.Invoke <FilePath>(input, context)?.FullPath; IView view; using (Stream stream = input.GetStream()) { view = GetViewFromStream(relativePath, stream, viewStartLocation, layoutLocation, viewEngine, pageActivator, htmlEncoder, pageFactoryProvider, hostingEnviornment.WebRootFileProvider, razorCompilationService); } // Render the view object model = _model == null ? input : _model.Invoke(input, context); using (StringWriter output = new StringWriter()) { Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext = GetViewContext(scope.ServiceProvider, view, model, input, context, output); viewContext.View.RenderAsync(viewContext).GetAwaiter().GetResult(); return context.GetDocument(input, output.ToString()); } } })); }
/// <inheritdoc /> public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context) { HtmlParser parser = new HtmlParser(); using (IJavaScriptEnginePool enginePool = context.GetJavaScriptEnginePool(x => { if (string.IsNullOrWhiteSpace(_highlightJsFile)) { x.ExecuteResource("highlight-all.js", typeof(Highlight)); } else { x.ExecuteFile(_highlightJsFile); } })) { return(inputs.AsParallel().Select(context, input => { try { using (Stream stream = input.GetStream()) { using (IHtmlDocument htmlDocument = parser.Parse(stream)) { foreach (AngleSharp.Dom.IElement element in htmlDocument.QuerySelectorAll(_codeQuerySelector)) { // Don't highlight anything that potentially is already highlighted if (element.ClassList.Contains("hljs")) { continue; } try { HighlightElement(enginePool, element); } catch (Exception innerEx) { if (innerEx.Message.Contains("Unknown language: ") && _warnOnMissingLanguage) { Trace.Warning($"Exception while highlighting source code: {innerEx.Message}"); } else { Trace.Information($"Exception while highlighting source code: {innerEx.Message}"); } } } Stream contentStream = context.GetContentStream(); using (StreamWriter writer = contentStream.GetWriter()) { htmlDocument.ToHtml(writer, HtmlMarkupFormatter.Instance); writer.Flush(); return context.GetDocument(input, contentStream); } } } } catch (Exception ex) { Trace.Warning("Exception while highlighting source code for {0}: {1}", input.SourceString(), ex.Message); return input; } }).ToList()); } }
protected override ExitCode RunCommand(Preprocessor preprocessor) { // Get the standard input stream _configOptions.Stdin = StandardInputReader.Read(); // Fix the root folder and other files DirectoryPath currentDirectory = Environment.CurrentDirectory; _configOptions.RootPath = _configOptions.RootPath == null ? currentDirectory : currentDirectory.Combine(_configOptions.RootPath); _logFilePath = _logFilePath == null ? null : _configOptions.RootPath.CombineFile(_logFilePath); _configOptions.ConfigFilePath = _configOptions.RootPath.CombineFile(_configOptions.ConfigFilePath ?? "config.wyam"); // Set up the log file if (_logFilePath != null) { Trace.AddListener(new SimpleFileTraceListener(_logFilePath.FullPath)); } // Get the engine and configurator EngineManager engineManager = EngineManager.Get(preprocessor, _configOptions); if (engineManager == null) { return(ExitCode.CommandLineError); } // Configure and execute if (!engineManager.Configure()) { return(ExitCode.ConfigurationError); } if (_verifyConfig) { Trace.Information("No errors. Exiting."); return(ExitCode.Normal); } Trace.Information($"Root path:{Environment.NewLine} {engineManager.Engine.FileSystem.RootPath}"); Trace.Information($"Input path(s):{Environment.NewLine} {string.Join(Environment.NewLine + " ", engineManager.Engine.FileSystem.InputPaths)}"); Trace.Information($"Output path:{Environment.NewLine} {engineManager.Engine.FileSystem.OutputPath}"); if (!engineManager.Execute()) { return(ExitCode.ExecutionError); } bool messagePump = false; // Start the preview server IDisposable previewServer = null; if (_preview) { messagePump = true; DirectoryPath previewPath = _previewRoot == null ? engineManager.Engine.FileSystem.GetOutputDirectory().Path : engineManager.Engine.FileSystem.GetOutputDirectory(_previewRoot).Path; previewServer = PreviewServer.Start(previewPath, _previewPort, _previewForceExtension); } // Start the watchers IDisposable inputFolderWatcher = null; IDisposable configFileWatcher = null; if (_watch) { messagePump = true; Trace.Information("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(); }); if (_configOptions.ConfigFilePath != null) { Trace.Information("Watching configuration file {0}", _configOptions.ConfigFilePath); configFileWatcher = new ActionFileSystemWatcher(engineManager.Engine.FileSystem.GetOutputDirectory().Path, new[] { _configOptions.ConfigFilePath.Directory }, false, _configOptions.ConfigFilePath.FileName.FullPath, path => { FilePath filePath = new FilePath(path); if (_configOptions.ConfigFilePath.Equals(filePath)) { _newEngine.Set(); _messageEvent.Set(); } }); } } // Start the message pump if an async process is running ExitCode exitCode = ExitCode.Normal; if (messagePump) { // 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 var thread = new Thread(() => { Trace.Information("Hit any key to exit"); Console.ReadKey(); _exit.Set(); _messageEvent.Set(); }) { IsBackground = true }; thread.Start(); } // Wait for activity while (true) { _messageEvent.WaitOne(); // Blocks the current thread until a signal if (_exit) { break; } // See if we need a new engine if (_newEngine) { // Get a new engine Trace.Information("Configuration file {0} has changed, re-running", _configOptions.ConfigFilePath); engineManager.Dispose(); engineManager = EngineManager.Get(preprocessor, _configOptions); // Configure and execute if (!engineManager.Configure()) { exitCode = ExitCode.ConfigurationError; break; } Console.WriteLine($"Root path:{Environment.NewLine} {engineManager.Engine.FileSystem.RootPath}"); Console.WriteLine($"Input path(s):{Environment.NewLine} {string.Join(Environment.NewLine + " ", engineManager.Engine.FileSystem.InputPaths)}"); Console.WriteLine($"Root path:{Environment.NewLine} {engineManager.Engine.FileSystem.OutputPath}"); if (!engineManager.Execute()) { exitCode = ExitCode.ExecutionError; break; } // Clear the changed files since we just re-ran string changedFile; while (_changedFiles.TryDequeue(out changedFile)) { } _newEngine.Unset(); } else { // Execute if files have changed HashSet <string> changedFiles = new HashSet <string>(); string changedFile; while (_changedFiles.TryDequeue(out changedFile)) { if (changedFiles.Add(changedFile)) { Trace.Verbose("{0} has changed", changedFile); } } if (changedFiles.Count > 0) { Trace.Information("{0} files have changed, re-executing", changedFiles.Count); if (!engineManager.Execute()) { exitCode = ExitCode.ExecutionError; break; } } } // Check one more time for exit if (_exit) { break; } Trace.Information("Hit any key to exit"); _messageEvent.Reset(); } // Shutdown Trace.Information("Shutting down"); engineManager.Dispose(); inputFolderWatcher?.Dispose(); configFileWatcher?.Dispose(); previewServer?.Dispose(); } return(exitCode); }