private ManifestItem UpdateItem(ManifestItem item, string sourceRelativePath)
        {
            var result = item.Clone();

            result.IsIncremental      = true;
            result.SourceRelativePath = sourceRelativePath;
            Parallel.ForEach(
                from ofi in result.OutputFiles.Values
                where ofi.LinkToPath != null
                where ofi.LinkToPath.Length > IncrementalContext.LastBaseDir.Length
                where ofi.LinkToPath.StartsWith(IncrementalContext.LastBaseDir)
                where (ofi.LinkToPath[IncrementalContext.LastBaseDir.Length] == '\\' || ofi.LinkToPath[IncrementalContext.LastBaseDir.Length] == '/')
                select ofi,
                new ParallelOptions {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            },
                ofi =>
            {
                IncrementalUtility.RetryIO(() =>
                {
                    var path = Path.Combine(IncrementalContext.BaseDir, IncrementalUtility.GetRandomEntry(IncrementalContext.BaseDir));
                    File.Copy(Environment.ExpandEnvironmentVariables(ofi.LinkToPath), Environment.ExpandEnvironmentVariables(path));
                    ofi.LinkToPath = path;
                });
            });

            return(result);
        }
예제 #2
0
 public override void Handle(HtmlDocument document, ManifestItem manifestItem, string inputFile, string outputFile)
 {
     foreach (var node in document.DocumentNode.Descendants())
     {
         if (!node.HasAttributes)
         {
             continue;
         }
         foreach (var attr in node.ChildAttributes("sourceFile"))
         {
             attr.Remove();
         }
         foreach (var attr in node.ChildAttributes("sourceStartLineNumber"))
         {
             attr.Remove();
         }
         foreach (var attr in node.ChildAttributes("sourceEndLineNumber"))
         {
             attr.Remove();
         }
         foreach (var attr in node.ChildAttributes("data-raw-source"))
         {
             attr.Remove();
         }
     }
 }
        private ManifestItem UpdateItem(ManifestItem item, string sourceRelativePath)
        {
            var result = item.Clone();

            result.IsIncremental      = true;
            result.SourceRelativePath = sourceRelativePath;

            // Copy when current base dir is not last base dir
            if (!FilePathComparerWithEnvironmentVariable.OSPlatformSensitiveRelativePathComparer.Equals(
                    IncrementalContext.BaseDir,
                    IncrementalContext.LastBaseDir))
            {
                foreach (var ofi in result.OutputFiles.Values)
                {
                    if (ofi.LinkToPath != null &&
                        ofi.LinkToPath.Length > IncrementalContext.LastBaseDir.Length &&
                        ofi.LinkToPath.StartsWith(IncrementalContext.LastBaseDir, StringComparison.Ordinal) &&
                        (ofi.LinkToPath[IncrementalContext.LastBaseDir.Length] == '\\' || ofi.LinkToPath[IncrementalContext.LastBaseDir.Length] == '/'))
                    {
                        IncrementalUtility.RetryIO(() =>
                        {
                            var path = Path.Combine(IncrementalContext.BaseDir, IncrementalUtility.GetRandomEntry(IncrementalContext.BaseDir));
                            File.Copy(Environment.ExpandEnvironmentVariables(ofi.LinkToPath), Environment.ExpandEnvironmentVariables(path));
                            ofi.LinkToPath = path;
                        });
                    }
                }
            }

            return(result);
        }
예제 #4
0
        protected override void HandleCore(HtmlDocument document, ManifestItem manifestItem, string inputFile, string outputFile)
        {
            _fileMapping[outputFile] = inputFile;

            // RFC 3986: relative-ref = relative-part [ "?" query ] [ "#" fragment ]
            _linksWithBookmark[outputFile] =
                (from node in GetNodesWithAttribute(document, "href")
                 let nocheck = node.GetAttributeValue("nocheck", null)
                               where !"bookmark".Equals(nocheck, StringComparison.OrdinalIgnoreCase)
                               let link = node.GetAttributeValue("href", null)
                                          let bookmark = UriUtility.GetFragment(link).TrimStart('#')
                                                         let decodedLink = RelativePath.TryParse(HttpUtility.UrlDecode(UriUtility.GetPath(link)))
                                                                           where !string.IsNullOrEmpty(bookmark) && !WhiteList.Contains(bookmark)
                                                                           where decodedLink != null
                                                                           select new LinkItem
            {
                Title = node.InnerText,
                Href = TransformPath(outputFile, decodedLink),
                Bookmark = bookmark,
                SourceFragment = WebUtility.HtmlDecode(node.GetAttributeValue("data-raw-source", null)),
                SourceFile = WebUtility.HtmlDecode(node.GetAttributeValue("sourceFile", null)),
                SourceLineNumber = node.GetAttributeValue("sourceStartLineNumber", 0),
                TargetLineNumber = node.Line
            }).ToList();
            var anchors = GetNodeAttribute(document, "id").Concat(GetNodeAttribute(document, "name"));

            _registeredBookmarks[outputFile] = new HashSet <string>(anchors);
        }
예제 #5
0
        public Manifest Process(Manifest manifest, string outputFolder)
        {
            if (outputFolder == null)
            {
                throw new ArgumentNullException("Base directory can not be null");
            }
            var indexData         = new SortedDictionary <string, SearchIndexItem>();
            var indexDataFilePath = Path.Combine(outputFolder, IndexFileName);
            var htmlFiles         = (from item in manifest.Files ?? Enumerable.Empty <ManifestItem>()
                                     from output in item.OutputFiles
                                     where item.DocumentType != "Toc" && output.Key.Equals(".html", StringComparison.OrdinalIgnoreCase)
                                     select output.Value.RelativePath).ToList();

            if (htmlFiles.Count == 0)
            {
                return(manifest);
            }

            Logger.LogInfo($"Extracting index data from {htmlFiles.Count} html files");
            foreach (var relativePath in htmlFiles)
            {
                var filePath = Path.Combine(outputFolder, relativePath);
                var html     = new HtmlDocument();
                Logger.LogDiagnostic($"Extracting index data from {filePath}");

                if (EnvironmentContext.FileAbstractLayer.Exists(filePath))
                {
                    try
                    {
                        using var stream = EnvironmentContext.FileAbstractLayer.OpenRead(filePath);
                        html.Load(stream, Encoding.UTF8);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning($"Warning: Can't load content from {filePath}: {ex.Message}");
                        continue;
                    }
                    var indexItem = ExtractItem(html, relativePath);
                    if (indexItem != null)
                    {
                        indexData[relativePath] = indexItem;
                    }
                }
            }
            JsonUtility.Serialize(indexDataFilePath, indexData, Formatting.Indented);

            // add index.json to manifest as resource file
            var manifestItem = new ManifestItem
            {
                DocumentType = "Resource",
            };

            manifestItem.OutputFiles.Add("resource", new OutputFileInfo
            {
                RelativePath = PathUtility.MakeRelativePath(outputFolder, indexDataFilePath),
            });

            manifest.Files?.Add(manifestItem);
            return(manifest);
        }
예제 #6
0
 public ManifestItemWithContext(ManifestItem item, FileModel model, IDocumentProcessor processor, TemplateBundle bundle)
 {
     Item           = item;
     FileModel      = model;
     Processor      = processor;
     TemplateBundle = bundle;
 }
예제 #7
0
        public void Handle(HtmlDocument document, ManifestItem manifestItem, string inputFile, string outputFile)
        {
            string phase = GetType().Name;

            using (new LoggerPhaseScope(phase))
            {
                HandleCore(document, manifestItem, inputFile, outputFile);
            }
        }
예제 #8
0
        public SystemMetadata Generate(ManifestItem item)
        {
            var attrs = new SystemMetadata
            {
                Language = Constants.DefaultLanguage,
            };

            string key  = GetFileKey(item.Key);
            var    file = (RelativePath)item.ModelFile;

            attrs.RelativePathToRoot = (RelativePath.Empty).MakeRelativeTo(file);
            attrs.PathFromRoot       = file.RemoveWorkingFolder();

            // 1. Root Toc is always in the top directory of output folder
            var rootToc = _toc.FirstOrDefault();

            if (rootToc != null)
            {
                var rootTocPath = rootToc.RemoveWorkingFolder();
                if (rootTocPath.SubdirectoryCount == 0)
                {
                    attrs.RootTocPath         = rootTocPath;
                    attrs.RootTocRelativePath = attrs.RootTocPath == null ? null : rootTocPath.MakeRelativeTo(file);
                    Logger.LogVerbose($"Root TOC file {rootTocPath} is found.");
                }
                else
                {
                    Logger.LogVerbose($"Root TOC file from output folder is not found, the toppest TOC file is {rootTocPath}");
                }
            }

            // 2. The algorithm of toc current article belongs to:
            //    a. If toc can be found in TocMap, return that toc
            //    b. Elsewise, get the nearest toc, **nearest** means nearest toc in **OUTPUT** folder
            var parentTocFiles = _context.GetTocFileKeySet(key)?.Select(s => _context.GetFilePath(s));
            var parentToc      = GetNearestToc(parentTocFiles);

            if (parentToc == null)
            {
                parentToc = GetDefaultToc(key);
            }

            if (parentToc != null)
            {
                var parentTocPath = parentToc.RemoveWorkingFolder();
                attrs.TocPath         = parentTocPath;
                attrs.TocRelativePath = attrs.TocPath == null ? null : parentTocPath.MakeRelativeTo(file);
                Logger.LogVerbose($"TOC file {parentTocPath} is found for {item.LocalPathFromRepoRoot}.");
            }
            else
            {
                Logger.LogVerbose($"TOC file for {item.LocalPathFromRepoRoot} is not found.");
            }

            return(attrs);
        }
예제 #9
0
        private IEnumerable <TransformModelOptions> GetOptionsForEachTemplate(ManifestItem item, IDocumentBuildContext context)
        {
            if (item == null)
            {
                yield break;
            }

            foreach (var template in Templates)
            {
                if (template.ContainsGetOptions)
                {
                    yield return(template.GetOptions(item.Model.Content));
                }
            }
        }
예제 #10
0
 protected override void HandleCore(HtmlDocument document, ManifestItem manifestItem, string inputFile, string outputFile)
 {
     foreach (var node in document.DocumentNode.Descendants())
     {
         if (!node.HasAttributes)
         {
             continue;
         }
         foreach (var remove in DebugInfoAttributes)
         {
             foreach (var attr in node.ChildAttributes(remove))
             {
                 attr.Remove();
             }
         }
     }
 }
        private ManifestItem UpdateItem(ManifestItem item, string sourceRelativePath)
        {
            var result = item.Clone();

            result.IsIncremental      = true;
            result.SourceRelativePath = sourceRelativePath;
            foreach (var ofi in result.OutputFiles.Values)
            {
                if (ofi.LinkToPath != null &&
                    ofi.LinkToPath.Length > IncrementalContext.LastBaseDir.Length &&
                    ofi.LinkToPath.StartsWith(IncrementalContext.LastBaseDir) &&
                    (ofi.LinkToPath[IncrementalContext.LastBaseDir.Length] == '\\' || ofi.LinkToPath[IncrementalContext.LastBaseDir.Length] == '/'))
                {
                    IncrementalUtility.RetryIO(() =>
                    {
                        var path = Path.Combine(IncrementalContext.BaseDir, IncrementalUtility.GetRandomEntry(IncrementalContext.BaseDir));
                        File.Copy(Environment.ExpandEnvironmentVariables(ofi.LinkToPath), Environment.ExpandEnvironmentVariables(path));
                        ofi.LinkToPath = path;
                    });
                }
            }
            return(result);
        }
예제 #12
0
 protected abstract void HandleCore(HtmlDocument document, ManifestItem manifestItem, string inputFile, string outputFile);
예제 #13
0
        private void TransformDocument(string result, string extension, IDocumentBuildContext context, string destFilePath, ManifestItem manifestItem, out List <XRefDetails> unresolvedXRefs)
        {
            Task <byte[]> hashTask;

            unresolvedXRefs = new List <XRefDetails>();
            using (var stream = EnvironmentContext.FileAbstractLayer.Create(destFilePath).WithMd5Hash(out hashTask))
                using (var sw = new StreamWriter(stream))
                {
                    if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase))
                    {
                        TransformHtml(context, result, manifestItem.SourceRelativePath, destFilePath, sw, out unresolvedXRefs);
                    }
                    else
                    {
                        sw.Write(result);
                    }
                }
            var ofi = new OutputFileInfo
            {
                RelativePath = destFilePath,
                LinkToPath   = GetLinkToPath(destFilePath),
                Hash         = Convert.ToBase64String(hashTask.Result)
            };

            manifestItem.OutputFiles.Add(extension, ofi);
        }
예제 #14
0
        /// <summary>
        /// Must guarantee thread safety
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        internal ManifestItem Transform(InternalManifestItem item)
        {
            if (item.Model == null || item.Model.Content == null)
            {
                throw new ArgumentNullException("Content for item.Model should not be null!");
            }
            var model = ConvertObjectToDictionary(item.Model.Content);

            model = AppendGlobalMetadata(model);
            if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportRawModel))
            {
                ExportModel(model, item.FileWithoutExtension, _settings.RawModelExportSettings);
            }

            var manifestItem = new ManifestItem
            {
                DocumentType       = item.DocumentType,
                SourceRelativePath = item.LocalPathFromRoot,
                OutputFiles        = new Dictionary <string, OutputFileInfo>(),
                Metadata           = item.Metadata,
            };
            var outputDirectory = _settings.OutputFolder ?? Environment.CurrentDirectory;

            // 1. process resource
            if (item.ResourceFile != null)
            {
                // Resource file has already been processed in its plugin
                manifestItem.OutputFiles.Add("resource", new OutputFileInfo
                {
                    RelativePath = item.ResourceFile,
                    LinkToPath   = null,
                    Hash         = null
                });
            }

            // 2. process model
            var templateBundle = _templateCollection[item.DocumentType];

            if (templateBundle == null)
            {
                return(manifestItem);
            }

            HashSet <string> missingUids = new HashSet <string>();

            // Must convert to JObject first as we leverage JsonProperty as the property name for the model
            foreach (var template in templateBundle.Templates)
            {
                if (!template.ContainsTemplateRenderer)
                {
                    continue;
                }

                var    extension  = template.Extension;
                string outputFile = item.FileWithoutExtension + extension;
                string outputPath = Path.Combine(outputDirectory, outputFile);
                var    dir        = Path.GetDirectoryName(outputPath);
                if (!string.IsNullOrEmpty(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                object viewModel = null;
                try
                {
                    viewModel = template.TransformModel(model);
                }
                catch (Exception e)
                {
                    // save raw model for further investigation:
                    var exportSettings = ApplyTemplateSettings.RawModelExportSettingsForDebug;
                    var rawModelPath   = ExportModel(model, item.FileWithoutExtension, exportSettings);
                    var message        = $"Error transforming model \"{rawModelPath}\" generated from \"{item.LocalPathFromRoot}\" using \"{template.ScriptName}\": {e.Message}";
                    Logger.LogError(message);
                    throw new DocumentException(message, e);
                }

                string result;
                try
                {
                    result = template.Transform(viewModel);
                }
                catch (Exception e)
                {
                    // save view model for further investigation:
                    var exportSettings = ApplyTemplateSettings.ViewModelExportSettingsForDebug;
                    var viewModelPath  = ExportModel(viewModel, outputFile, exportSettings);
                    var message        = $"Error applying template \"{template.Name}\" to view model \"{viewModelPath}\" generated from \"{item.LocalPathFromRoot}\": {e.Message}";
                    Logger.LogError(message);
                    throw new DocumentException(message, e);
                }

                if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportViewModel))
                {
                    ExportModel(viewModel, outputFile, _settings.ViewModelExportSettings);
                }

                if (_settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument))
                {
                    if (string.IsNullOrWhiteSpace(result))
                    {
                        // TODO: WHAT to do if is transformed to empty string? STILL creat empty file?
                        var exportSettings = ApplyTemplateSettings.ViewModelExportSettingsForDebug;
                        var viewModelPath  = ExportModel(viewModel, outputFile, exportSettings);
                        Logger.LogWarning($"Model \"{viewModelPath}\" is transformed to empty string with template \"{template.Name}\"");
                        File.WriteAllText(outputPath, string.Empty);
                    }
                    else
                    {
                        TransformDocument(result, extension, _context, outputPath, outputFile, missingUids, manifestItem);
                        Logger.LogDiagnostic($"Transformed model \"{item.LocalPathFromRoot}\" to \"{outputPath}\".");
                    }
                }
            }

            if (missingUids.Count > 0)
            {
                var uids = string.Join(", ", missingUids.Select(s => $"\"{s}\""));
                Logger.LogWarning($"Unable to resolve cross-reference {uids}");
            }

            return(manifestItem);
        }
예제 #15
0
        private static void TransformDocument(string result, string extension, IDocumentBuildContext context, string outputPath, string relativeOutputPath, HashSet <string> missingUids, ManifestItem manifestItem)
        {
            var subDirectory = Path.GetDirectoryName(outputPath);

            if (!string.IsNullOrEmpty(subDirectory) &&
                !Directory.Exists(subDirectory))
            {
                Directory.CreateDirectory(subDirectory);
            }

            Task <byte[]> hashTask;

            using (var stream = File.Create(outputPath).WithMd5Hash(out hashTask))
                using (var sw = new StreamWriter(stream))
                {
                    if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase))
                    {
                        try
                        {
                            TranformHtml(context, result, relativeOutputPath, sw);
                        }
                        catch (AggregateException e)
                        {
                            e.Handle(s =>
                            {
                                var xrefExcetpion = s as CrossReferenceNotResolvedException;
                                if (xrefExcetpion != null)
                                {
                                    missingUids.Add(xrefExcetpion.UidRawText);
                                    return(true);
                                }
                                else
                                {
                                    return(false);
                                }
                            });
                        }
                    }
                    else
                    {
                        sw.Write(result);
                    }
                }
            manifestItem.OutputFiles.Add(extension, new OutputFileInfo
            {
                RelativePath = relativeOutputPath,
                LinkToPath   = null,
                Hash         = Convert.ToBase64String(hashTask.Result)
            });
        }
예제 #16
0
        private TemplateManifestItem TransformItem(ManifestItem item, IDocumentBuildContext context, ApplyTemplateSettings settings, SystemMetadataGenerator systemAttributeGenerator)
        {
            if (settings.Options.HasFlag(ApplyTemplateOptions.ExportRawModel))
            {
                ExportModel(item.Model.Content, item.ModelFile, settings.RawModelExportSettings);
            }

            if (item.Model == null || item.Model.Content == null)
            {
                throw new ArgumentNullException("Content for item.Model should not be null!");
            }
            var manifestItem = new TemplateManifestItem
            {
                DocumentType = item.DocumentType,
                OriginalFile = item.LocalPathFromRepoRoot,
                OutputFiles  = new Dictionary <string, string>()
            };
            var outputDirectory = settings.OutputFolder ?? Environment.CurrentDirectory;

            if (!IsEmpty)
            {
                HashSet <string> missingUids = new HashSet <string>();

                // Must convert to JObject first as we leverage JsonProperty as the property name for the model
                var model     = ConvertToObjectHelper.ConvertStrongTypeToJObject(item.Model.Content);
                var templates = Templates[item.DocumentType];

                // 1. process model
                if (templates != null)
                {
                    var systemAttrs = systemAttributeGenerator.Generate(item);
                    foreach (var template in templates)
                    {
                        var    extension  = template.Extension;
                        string outputFile = Path.ChangeExtension(item.ModelFile, extension);
                        string outputPath = Path.Combine(outputDirectory, outputFile);
                        var    dir        = Path.GetDirectoryName(outputPath);
                        if (!string.IsNullOrEmpty(dir))
                        {
                            Directory.CreateDirectory(dir);
                        }
                        object viewModel = null;
                        try
                        {
                            viewModel = template.TransformModel(model, systemAttrs, _global);
                        }
                        catch (Exception e)
                        {
                            // save raw model for further investigation:
                            var exportSettings = ApplyTemplateSettings.RawModelExportSettingsForDebug;
                            var rawModelPath   = ExportModel(model, item.ModelFile, exportSettings);
                            throw new DocumentException($"Error transforming model \"{rawModelPath}\" generated from \"{item.LocalPathFromRepoRoot}\" using \"{template.ScriptName}\": {e.Message}");
                        }

                        string result;
                        try
                        {
                            result = template.Transform(viewModel);
                        }
                        catch (Exception e)
                        {
                            // save view model for further investigation:
                            var exportSettings = ApplyTemplateSettings.ViewModelExportSettingsForDebug;
                            var viewModelPath  = ExportModel(viewModel, outputFile, exportSettings);
                            throw new DocumentException($"Error applying template \"{template.Name}\" to view model \"{viewModelPath}\" generated from \"{item.LocalPathFromRepoRoot}\": {e.Message}");
                        }

                        if (settings.Options.HasFlag(ApplyTemplateOptions.ExportViewModel))
                        {
                            ExportModel(viewModel, outputFile, settings.ViewModelExportSettings);
                        }

                        if (settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument))
                        {
                            if (string.IsNullOrWhiteSpace(result))
                            {
                                // TODO: WHAT to do if is transformed to empty string? STILL creat empty file?
                                Logger.LogWarning($"Model \"{item.ModelFile}\" is transformed to empty string with template \"{template.Name}\"");
                                File.WriteAllText(outputPath, string.Empty);
                            }
                            else
                            {
                                TransformDocument(result, extension, context, outputPath, item.ModelFile, missingUids);
                                Logger.Log(LogLevel.Verbose, $"Transformed model \"{item.LocalPathFromRepoRoot}\" to \"{outputPath}\".");
                            }

                            manifestItem.OutputFiles.Add(extension, outputFile);
                        }
                    }
                }

                if (missingUids.Count > 0)
                {
                    var uids = string.Join(", ", missingUids.Select(s => $"\"{s}\""));
                    Logger.LogWarning($"Unable to resolve cross-reference {uids} for \"{manifestItem.OriginalFile.ToDisplayPath()}\"");
                }
            }

            // 2. process resource
            if (item.ResourceFile != null)
            {
                // Resource file has already been processed in its plugin
                manifestItem.OutputFiles.Add("resource", item.ResourceFile);
            }

            return(manifestItem);
        }
예제 #17
0
 public TransformModelOptions GetOptions(ManifestItem item, IDocumentBuildContext context)
 {
     return(MergeOptions(GetOptionsForEachTemplate(item, context)));
 }
예제 #18
0
        private void TransformDocument(string result, string extension, IDocumentBuildContext context, string destFilePath, HashSet <string> missingUids, ManifestItem manifestItem)
        {
            Task <byte[]> hashTask;

            using (var stream = EnvironmentContext.FileAbstractLayer.Create(destFilePath).WithMd5Hash(out hashTask))
                using (var sw = new StreamWriter(stream))
                {
                    if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase))
                    {
                        try
                        {
                            TransformHtml(context, result, manifestItem.SourceRelativePath, destFilePath, sw);
                        }
                        catch (AggregateException e)
                        {
                            e.Handle(s =>
                            {
                                var xrefExcetpion = s as CrossReferenceNotResolvedException;
                                if (xrefExcetpion != null)
                                {
                                    missingUids.Add(xrefExcetpion.UidRawText);
                                    return(true);
                                }
                                else
                                {
                                    return(false);
                                }
                            });
                        }
                    }
                    else
                    {
                        sw.Write(result);
                    }
                }
            var ofi = new OutputFileInfo
            {
                RelativePath = destFilePath,
                LinkToPath   = GetLinkToPath(destFilePath),
                Hash         = Convert.ToBase64String(hashTask.Result)
            };

            manifestItem.OutputFiles.Add(extension, ofi);
        }
예제 #19
0
        private static FileModel Load(
            IDocumentProcessor processor,
            ImmutableDictionary <string, object> metadata,
            FileMetadata fileMetadata,
            FileAndType file,
            bool canProcessorIncremental,
            IDictionary <string, XRefSpec> xrefSpecMap,
            IEnumerable <ManifestItem> manifestItems,
            DependencyGraph dg,
            DocumentBuildContext context)
        {
            using (new LoggerFileScope(file.File))
            {
                Logger.LogDiagnostic($"Processor {processor.Name}, File {file.FullPath}: Loading...");

                if (canProcessorIncremental)
                {
                    ChangeKindWithDependency ck;
                    string fileKey = ((RelativePath)file.File).GetPathFromWorkingFolder().ToString();
                    if (context.ChangeDict.TryGetValue(fileKey, out ck))
                    {
                        if (ck == ChangeKindWithDependency.Deleted)
                        {
                            return(null);
                        }
                        if (ck == ChangeKindWithDependency.None)
                        {
                            Logger.LogDiagnostic($"Processor {processor.Name}, File {file.FullPath}: Check incremental...");
                            if (((ISupportIncrementalBuild)processor).CanIncrementalBuild(file) &&
                                processor.BuildSteps.Cast <ISupportIncrementalBuild>().All(step => step.CanIncrementalBuild(file)))
                            {
                                Logger.LogDiagnostic($"Processor {processor.Name}, File {file.FullPath}: Skip build by incremental.");

                                // restore filemap
                                context.FileMap[fileKey] = ((RelativePath)file.File).GetPathFromWorkingFolder();

                                // restore xrefspec
                                var specs = xrefSpecMap?.Values?.Where(spec => spec.Href == fileKey);
                                if (specs != null)
                                {
                                    foreach (var spec in specs)
                                    {
                                        context.XRefSpecMap[spec.Uid] = spec;
                                    }
                                }

                                // restore manifestitem
                                ManifestItem item = manifestItems?.SingleOrDefault(i => i.SourceRelativePath == file.File);
                                if (item != null)
                                {
                                    context.ManifestItems.Add(item);
                                }

                                // restore dependency graph
                                if (dg.HasDependency(fileKey))
                                {
                                    context.DependencyGraph.ReportDependency(fileKey, dg.GetDirectDependency(fileKey));
                                }
                                return(null);
                            }
                            Logger.LogDiagnostic($"Processor {processor.Name}, File {file.FullPath}: Incremental not available.");
                        }
                    }
                }

                var path = Path.Combine(file.BaseDir, file.File);
                metadata = ApplyFileMetadata(path, metadata, fileMetadata);
                try
                {
                    return(processor.Load(file, metadata));
                }
                catch (Exception)
                {
                    Logger.LogError($"Unable to load file: {file.File} via processor: {processor.Name}.");
                    throw;
                }
            }
        }
예제 #20
0
 public abstract void Handle(HtmlDocument document, ManifestItem manifestItem, string inputFile, string outputFile);
예제 #21
0
        /// <summary>
        /// Must guarantee thread safety
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        internal ManifestItem Transform(InternalManifestItem item)
        {
            if (item.Model == null || item.Model.Content == null)
            {
                throw new ArgumentNullException("Content for item.Model should not be null!");
            }
            var model = ConvertObjectToDictionary(item.Model.Content);

            model = AppendGlobalMetadata(model);
            if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportRawModel))
            {
                ExportModel(model, item.FileWithoutExtension, _settings.RawModelExportSettings);
            }

            var manifestItem = new ManifestItem
            {
                DocumentType       = item.DocumentType,
                SourceRelativePath = item.LocalPathFromRoot,
                Metadata           = item.Metadata,
                Version            = _context.VersionName,
            };
            var outputDirectory = _settings.OutputFolder ?? Directory.GetCurrentDirectory();

            // 1. process resource
            if (item.ResourceFile != null)
            {
                // Resource file has already been processed in its plugin
                var ofi = new OutputFileInfo
                {
                    RelativePath = item.ResourceFile,
                    LinkToPath   = GetLinkToPath(item.ResourceFile),
                };
                manifestItem.OutputFiles.Add("resource", ofi);
            }

            // 2. process model
            var templateBundle = _templateCollection[item.DocumentType];

            if (templateBundle == null)
            {
                return(manifestItem);
            }

            HashSet <string> missingUids = new HashSet <string>();

            // Must convert to JObject first as we leverage JsonProperty as the property name for the model
            foreach (var template in templateBundle.Templates)
            {
                if (!template.ContainsTemplateRenderer)
                {
                    continue;
                }
                try
                {
                    var    extension  = template.Extension;
                    string outputFile = item.FileWithoutExtension + extension;
                    object viewModel  = null;
                    try
                    {
                        viewModel = template.TransformModel(model);
                    }
                    catch (Exception e)
                    {
                        string message;
                        if (_settings.DebugMode)
                        {
                            // save raw model for further investigation:
                            var rawModelPath = ExportModel(model, item.FileWithoutExtension, _settings.RawModelExportSettingsForDebug);
                            message = $"Error transforming model \"{rawModelPath}\" generated from \"{item.LocalPathFromRoot}\" using \"{template.ScriptName}\". {e.Message}";
                        }
                        else
                        {
                            message = $"Error transforming model generated from \"{item.LocalPathFromRoot}\" using \"{template.ScriptName}\". To get the detailed raw model, please run docfx with debug mode --debug. {e.Message} ";
                        }

                        Logger.LogError(message);
                        throw new DocumentException(message, e);
                    }

                    string result;
                    try
                    {
                        result = template.Transform(viewModel);
                    }
                    catch (Exception e)
                    {
                        string message;
                        if (_settings.DebugMode)
                        {
                            // save view model for further investigation:
                            var viewModelPath = ExportModel(viewModel, outputFile, _settings.ViewModelExportSettingsForDebug);
                            message = $"Error applying template \"{template.Name}\" to view model \"{viewModelPath}\" generated from \"{item.LocalPathFromRoot}\". {e.Message}";
                        }
                        else
                        {
                            message = $"Error applying template \"{template.Name}\" generated from \"{item.LocalPathFromRoot}\". To get the detailed view model, please run docfx with debug mode --debug. {e.Message}";
                        }

                        Logger.LogError(message);
                        throw new DocumentException(message, e);
                    }

                    if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportViewModel))
                    {
                        ExportModel(viewModel, outputFile, _settings.ViewModelExportSettings);
                    }

                    if (_settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument))
                    {
                        if (string.IsNullOrWhiteSpace(result))
                        {
                            string message;
                            if (_settings.DebugMode)
                            {
                                var viewModelPath = ExportModel(viewModel, outputFile, _settings.ViewModelExportSettingsForDebug);
                                message = $"Model \"{viewModelPath}\" is transformed to empty string with template \"{template.Name}\"";
                            }
                            else
                            {
                                message = $"Model is transformed to empty string with template \"{template.Name}\". To get the detailed view model, please run docfx with debug mode --debug";
                            }
                            Logger.LogWarning(message);
                        }

                        TransformDocument(result ?? string.Empty, extension, _context, outputFile, missingUids, manifestItem);
                        Logger.LogDiagnostic($"Transformed model \"{item.LocalPathFromRoot}\" to \"{outputFile}\".");
                    }
                }
                catch (PathTooLongException e)
                {
                    var message = $"Error processing {item.LocalPathFromRoot}: {e.Message}";
                    throw new PathTooLongException(message, e);
                }
            }

            if (missingUids.Count > 0)
            {
                var uids = string.Join(", ", missingUids.Select(s => $"\"{s}\""));
                Logger.LogWarning($"Invalid cross reference {uids}.", null, item.LocalPathFromRoot);
            }

            return(manifestItem);
        }
예제 #22
0
 public ManifestItemWithContext(ManifestItem item, FileModel model, IDocumentProcessor processor)
 {
     Item      = item;
     FileModel = model;
     Processor = processor;
 }