public void SaveIntermediateModel(IncrementalBuildContext incrementalContext) { if (!ShouldTraceIncrementalInfo) { return; } var processor = (ISupportIncrementalDocumentProcessor)Processor; var mi = incrementalContext.GetModelLoadInfo(this); var lmm = incrementalContext.GetLastIntermediateModelManifest(this); var cmm = incrementalContext.GetCurrentIntermediateModelManifest(this); foreach (var pair in mi) { IncrementalUtility.RetryIO(() => { string fileName = IncrementalUtility.GetRandomEntry(incrementalContext.BaseDir); if (pair.Value == null) { if (lmm == null) { throw new BuildCacheException($"Full build hasn't loaded model {pair.Key}"); } string lfn; if (!lmm.Models.TryGetValue(pair.Key, out lfn)) { throw new BuildCacheException($"Last build hasn't loaded model {pair.Key}"); } File.Move(Path.Combine(incrementalContext.LastBaseDir, lfn), Path.Combine(incrementalContext.BaseDir, fileName)); } else { var key = TypeForwardedToRelativePath.NormalizedWorkingFolder + pair.Key; var model = Models.Find(m => m.Key == key); using (var stream = File.Create(Path.Combine(incrementalContext.BaseDir, fileName))) { processor.SaveIntermediateModel(model, stream); } } cmm.Models.Add(pair.Key, fileName); }); } }
public IEnumerable <FileModel> LoadIntermediateModel(IncrementalBuildContext incrementalContext, string fileName) { if (!CanIncrementalBuild) { yield break; } var processor = (ISupportIncrementalDocumentProcessor)Processor; var cmm = incrementalContext.GetCurrentIntermediateModelManifest(this); if (!cmm.Models.TryGetValue(fileName, out List <ModelManifestItem> cfn)) { throw new BuildCacheException($"Last build hasn't loaded model {fileName}"); } foreach (var item in cfn) { using var stream = File.OpenRead( Path.Combine(Environment.ExpandEnvironmentVariables(incrementalContext.BaseDir), item.FilePath)); yield return(processor.LoadIntermediateModel(stream)); } }
internal static void RelayBuildMessage(IncrementalBuildContext context, IEnumerable <HostService> hostServices, BuildPhase phase) { var falseSet = new HashSet <string>(from h in hostServices where !h.CanIncrementalBuild from f in h.Models select f.OriginalFileAndType.File, FilePathComparer.OSPlatformSensitiveStringComparer); var fileSet = new HashSet <string>(from h in hostServices where h.CanIncrementalBuild from f in GetFilesToRelayMessages(context, h) where !falseSet.Contains(f) select f, FilePathComparer.OSPlatformSensitiveStringComparer); var lastBuildMessageInfo = GetPhaseMessageInfo(context.LastBuildVersionInfo?.BuildMessage, phase); foreach (var file in fileSet) { lastBuildMessageInfo.Replay(file); } }
private void Prepare( DocumentBuildParameters parameters, DocumentBuildContext context, TemplateProcessor templateProcessor, string markdownServiceContextHash, out IHostServiceCreator hostServiceCreator, out PhaseProcessor phaseProcessor) { if (IntermediateFolder != null && parameters.ApplyTemplateSettings.TransformDocument) { using (new LoggerPhaseScope("CreateIncrementalBuildContext", false)) using (new PerformanceScope("CreateIncrementalBuildContext", LogLevel.Verbose)) { context.IncrementalBuildContext = IncrementalBuildContext.Create(parameters, CurrentBuildInfo, LastBuildInfo, IntermediateFolder, markdownServiceContextHash); } hostServiceCreator = new HostServiceCreatorWithIncremental(context); phaseProcessor = new PhaseProcessor { Handlers = { new CompilePhaseHandler(context).WithIncremental(), new LinkPhaseHandler(context, templateProcessor).WithIncremental(), } }; } else { hostServiceCreator = new HostServiceCreator(context); phaseProcessor = new PhaseProcessor { Handlers = { new CompilePhaseHandler(context), new LinkPhaseHandler(context, templateProcessor), } }; } }
public void SaveIntermediateModel(IncrementalBuildContext incrementalContext) { if (!ShouldTraceIncrementalInfo) { return; } var processor = (ISupportIncrementalDocumentProcessor)Processor; var mi = incrementalContext.GetModelLoadInfo(this); var lmm = incrementalContext.GetLastIntermediateModelManifest(this); var cmm = incrementalContext.GetCurrentIntermediateModelManifest(this); Parallel.ForEach(mi, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, pair => { IncrementalUtility.RetryIO(() => { var items = new List <ModelManifestItem>(); if (pair.Value == null) { if (lmm == null) { throw new BuildCacheException($"Full build hasn't loaded model {pair.Key}"); } if (!lmm.Models.TryGetValue(pair.Key, out List <ModelManifestItem> lfn)) { throw new BuildCacheException($"Last build hasn't loaded model {pair.Key}"); } if (FilePathComparerWithEnvironmentVariable.OSPlatformSensitiveRelativePathComparer.Equals( incrementalContext.BaseDir, incrementalContext.LastBaseDir)) { items.AddRange(lfn); } else { foreach (var item in lfn) { // use copy rather than move because if the build failed, the intermediate files of last successful build shouldn't be corrupted. string fileName = IncrementalUtility.GetRandomEntry(incrementalContext.BaseDir); File.Copy( Path.Combine(Environment.ExpandEnvironmentVariables(incrementalContext.LastBaseDir), item.FilePath), Path.Combine(Environment.ExpandEnvironmentVariables(incrementalContext.BaseDir), fileName)); items.Add(new ModelManifestItem() { SourceFilePath = item.SourceFilePath, FilePath = fileName }); } } } else { var models = Models.Where(m => m.OriginalFileAndType.File == pair.Key).ToList(); foreach (var model in models) { string fileName = IncrementalUtility.GetRandomEntry(incrementalContext.BaseDir); using (var stream = File.Create( Path.Combine( Environment.ExpandEnvironmentVariables(incrementalContext.BaseDir), fileName))) { processor.SaveIntermediateModel(model, stream); } items.Add(new ModelManifestItem() { SourceFilePath = model.FileAndType.File, FilePath = fileName }); } } lock (cmm) { cmm.Models.Add(pair.Key, items); } }); }); }
public void ReloadUnloadedModels(IncrementalBuildContext incrementalContext, BuildPhase loadedAt) { var mi = incrementalContext.GetModelLoadInfo(this); ReloadUnloadedModelsPerCondition(incrementalContext, loadedAt, f => mi[f] == null); }
private Manifest BuildCore(DocumentBuildParameters parameters) { using (new LoggerPhaseScope(PhaseName, true)) { Logger.LogInfo($"Max parallelism is {parameters.MaxParallelism}."); Directory.CreateDirectory(parameters.OutputBaseDir); var context = new DocumentBuildContext( Path.Combine(Directory.GetCurrentDirectory(), parameters.OutputBaseDir), parameters.Files.EnumerateFiles(), parameters.ExternalReferencePackages, parameters.XRefMaps, parameters.MaxParallelism, parameters.Files.DefaultBaseDir); if (ShouldTraceIncrementalInfo) { context.IncrementalBuildContext = IncrementalBuildContext.Create(parameters, CurrentBuildInfo, LastBuildInfo, IntermediateFolder); Logger.RegisterListener(context.IncrementalBuildContext.CurrentBuildVersionInfo.BuildMessage.GetListener()); if (context.IncrementalBuildContext.CanVersionIncremental) { context.IncrementalBuildContext.LoadChanges(); Logger.LogVerbose($"Before expanding dependency before build, changes: {JsonUtility.Serialize(context.IncrementalBuildContext.ChangeDict, Formatting.Indented)}"); var dependencyGraph = context.IncrementalBuildContext.LastBuildVersionInfo.Dependency; context.IncrementalBuildContext.ExpandDependency(dependencyGraph, d => dependencyGraph.DependencyTypes[d.Type].Phase == BuildPhase.Build || dependencyGraph.DependencyTypes[d.Type].TriggerBuild); Logger.LogVerbose($"After expanding dependency before build, changes: {JsonUtility.Serialize(context.IncrementalBuildContext.ChangeDict, Formatting.Indented)}"); } } Logger.LogVerbose("Start building document..."); // Start building document... List <HostService> hostServices = null; try { using (var templateProcessor = parameters.TemplateManager?.GetTemplateProcessor(context, parameters.MaxParallelism) ?? TemplateProcessor.DefaultProcessor) { IMarkdownService markdownService; using (new LoggerPhaseScope("CreateMarkdownService", true)) { markdownService = CreateMarkdownService(parameters, templateProcessor.Tokens.ToImmutableDictionary()); } using (new LoggerPhaseScope("Load", true)) { hostServices = GetInnerContexts(parameters, Processors, templateProcessor, markdownService, context).ToList(); } var manifest = BuildCore(hostServices, context, parameters.VersionName).ToList(); // Use manifest from now on using (new LoggerPhaseScope("UpdateContext", true)) { UpdateContext(context); } // Run getOptions from Template using (new LoggerPhaseScope("FeedOptions", true)) { FeedOptions(manifest, context); } // Template can feed back xref map, actually, the anchor # location can only be determined in template using (new LoggerPhaseScope("FeedXRefMap", true)) { FeedXRefMap(manifest, context); } using (new LoggerPhaseScope("UpdateHref", true)) { UpdateHref(manifest, context); } // Afterwards, m.Item.Model.Content is always IDictionary using (new LoggerPhaseScope("ApplySystemMetadata", true)) { ApplySystemMetadata(manifest, context); } // Register global variables after href are all updated IDictionary <string, object> globalVariables; using (new LoggerPhaseScope("FeedGlobalVariables", true)) { globalVariables = FeedGlobalVariables(templateProcessor.Tokens, manifest, context); } // processor to add global variable to the model foreach (var m in templateProcessor.Process(manifest.Select(s => s.Item).ToList(), context, parameters.ApplyTemplateSettings, globalVariables)) { context.ManifestItems.Add(m); } return(new Manifest { Files = context.ManifestItems.ToList(), Homepages = GetHomepages(context), XRefMap = ExportXRefMap(parameters, context), SourceBasePath = TypeForwardedToStringExtension.ToNormalizedPath(EnvironmentContext.BaseDirectory) }); } } finally { if (hostServices != null) { foreach (var item in hostServices) { Cleanup(item); item.Dispose(); } } } } }