private void ConvertTocModelToHtmlModel(IList <TocModel> tocModels, IList <HtmlModel> htmlModels, ConcurrentBag <string> tocHtmls) { foreach (var tocModel in tocModels) { var htmlModel = new HtmlModel { Title = tocModel.Title, ExternalLink = tocModel.ExternalLink, HtmlFilePath = tocModel.HtmlFilePath.RemoveUrlQueryString().RemoveUrlBookmark(), Children = new List <HtmlModel>() }; if (!string.IsNullOrEmpty(tocModel.HtmlFilePath)) { tocHtmls.Add(tocModel.HtmlFilePath.RemoveUrlQueryString().RemoveUrlBookmark()); } if (tocModel.Children != null && tocModel.Children.Any()) { ConvertTocModelToHtmlModel(tocModel.Children, htmlModel.Children, tocHtmls); } htmlModels.Add(htmlModel); } }
private void ConvertCore(string basePath) { Logger.LogVerbose($"Reading files from {basePath}"); HtmlTransformer(basePath); var manifest = JsonUtility.Deserialize <Manifest>(Path.Combine(basePath, ManifestConstants.ManifestFileName)); if (manifest == null) { Logger.LogError("Manifest file is not found."); throw new FileNotFoundException("Manifest file is not found."); } if (manifest.Files == null || manifest.Files.Count == 0) { Logger.LogWarning($"There is no file in manifest under {_pdfOptions.SourceDirectory}"); return; } var tocFiles = FindTocInManifest(manifest); if (tocFiles.Count > 0) { Logger.LogVerbose($"Found {tocFiles.Count} TOC.json files, will generate pdf."); } else { Logger.LogWarning("No TOC file is included, no PDF file will be generated."); return; } var tocHtmls = new ConcurrentBag <string>(); IDictionary <string, PdfInformation> pdfInformations = new ConcurrentDictionary <string, PdfInformation>(); var manifestItems = manifest.Files.Where(f => IsType(f, ManifestItemType.Content)).ToArray(); var manifestUrlCache = new UrlCache(basePath, manifestItems); Parallel.ForEach( tocFiles, new ParallelOptions { MaxDegreeOfParallelism = _pdfOptions.PdfConvertParallelism }, tocFile => { var tocJson = ManifestUtility.GetRelativePath(tocFile, OutputType.TocJson); var tocAssetId = ManifestUtility.GetAssetId(tocFile); try { Logger.LogVerbose($"Starting to handle {tocJson}."); var tocFilePath = NormalizeFilePath(tocJson); var tocPageFilePath = Path.Combine(basePath, Path.GetDirectoryName(tocFilePath), TocPageFileName); var tocModels = LoadTocModels(basePath, tocFile) ?? new List <TocModel>(); var currentTocHtmls = new ConcurrentBag <string>(); var htmlModels = BuildHtmlModels(basePath, tocModels, currentTocHtmls); HtmlNotInTocTransformer(basePath, manifestUrlCache, currentTocHtmls); if (_pdfOptions.GenerateAppendices) { currentTocHtmls.AsParallel().ForAll(tocHtmls.Add); } if (File.Exists(tocPageFilePath)) { RemoveQueryStringAndBookmarkTransformer(tocPageFilePath); AbsolutePathInTocPageFileTransformer(tocPageFilePath); htmlModels.Insert(0, new HtmlModel { Title = _pdfOptions.TocTitle, HtmlFilePath = tocPageFilePath }); } var coverPage = FindSiblingCoverPageInManifest(manifest, tocFile); if (coverPage != null) { var coverPageHtmlRelativeFilePath = coverPage.OutputFiles[".html"].RelativePath; var coverPageHtmlFilePath = Path.Combine(basePath, coverPageHtmlRelativeFilePath); if (File.Exists(coverPageHtmlFilePath)) { htmlModels.Insert(0, new HtmlModel { Title = _pdfOptions.CoverPageTitle, HtmlFilePath = coverPageHtmlFilePath }); } } if (_pdfOptions.ExcludeTocs == null || _pdfOptions.ExcludeTocs.All(p => NormalizeFilePath(p) != tocFilePath)) { var pdfNameFragments = new List <string> { _pdfOptions.PdfDocsetName }; if (!string.IsNullOrEmpty(_pdfOptions.Locale)) { pdfNameFragments.Add(_pdfOptions.Locale); } // TODO: not consistent with OPS logic Path.ChangeExtension(tocAssetId, FileExtensions.PdfExtension).Replace('/', '_') // TODO: need to update the logic in OPS when merging with OPS if (!string.IsNullOrWhiteSpace(tocAssetId)) { var subFolder = Path.GetDirectoryName(tocAssetId); if (!string.IsNullOrEmpty(subFolder)) { pdfNameFragments.Add(subFolder.Replace('/', '_')); } } var pdfName = pdfNameFragments.ToDelimitedString("_") + FileExtensions.PdfExtension; ConvertCore(basePath, pdfName, htmlModels); Logger.LogInfo($"{pdfName} is generated based on {tocJson} under folder {_pdfOptions.DestDirectory}"); pdfInformations.Add( pdfName, new PdfInformation { DocsetName = _pdfOptions.PdfDocsetName, TocFiles = new string[] { tocFile.SourceRelativePath }, Version = tocFile.Group, AssetId = tocAssetId, }); } else { Logger.LogVerbose($"Skipped to convert {tocJson} to pdf because of custom exclude tocs."); } Logger.LogVerbose($"Finished to handle {tocJson}."); } catch (Exception ex) { Logger.LogError($"Error happen when converting {tocJson} to Pdf. Details: {ex.ToString()}"); } }); using (var fileStream = new FileStream(Path.Combine(_pdfOptions.DestDirectory, _pdfOptions.PdfDocsetName + FileExtensions.JsonExtension), FileMode.Create, FileAccess.Write)) { using var ws = new StreamWriter(fileStream); JsonUtility.Serialize(ws, pdfInformations); } if (_pdfOptions.GenerateAppendices) { var otherConceptuals = ManifestHtmlsExceptTocHtmls(manifest, tocHtmls); if (otherConceptuals.Count > 0) { var htmlModels = new List <HtmlModel>(); var htmlModel = new HtmlModel { Title = "appendices", Children = otherConceptuals.Select((other, index) => new HtmlModel { Title = $"Appendix {index + 1}", HtmlFilePath = other }).ToList() }; htmlModels.Add(htmlModel); Logger.LogVerbose("Starting to convert appendices to pdf."); ConvertCore(basePath, "appendices", htmlModels); } } else { Logger.LogVerbose("Skipped to convert appendices to pdf."); } }