internal bool SaveMetadataAfterEditSource(string editedFilePath) { if (!File.Exists(editedFilePath)) { return(true); } using (Stream metadataFileStream = File.OpenRead(editedFilePath)) { try { using (var str = ManifestUtility.ReadManifest(metadataFileStream)) { Manifest manifest = Manifest.ReadFrom(str, true); var newMetadata = new EditablePackageMetadata(manifest.Metadata, _uiServices); PackageMetadata = newMetadata; return(true); } } catch (Exception exception) { bool confirmExit = UIServices.ConfirmCloseEditor( "There is an error in the metadata source.", exception.GetBaseException().Message + Environment.NewLine + Environment.NewLine + "Do you want to cancel your changes and return?"); return(confirmExit); } } }
public void Handle(List <PostProcessor> postProcessors, Manifest manifest, string outputFolder) { if (postProcessors == null) { throw new ArgumentNullException(nameof(postProcessors)); } if (manifest == null) { throw new ArgumentNullException(nameof(manifest)); } if (outputFolder == null) { throw new ArgumentNullException(nameof(outputFolder)); } using (new LoggerPhaseScope("HandlePostProcessors", LogLevel.Verbose)) { foreach (var postProcessor in postProcessors) { using (new LoggerPhaseScope($"Processing {postProcessor.ContractName}", LogLevel.Verbose)) { manifest = postProcessor.Processor.Process(manifest, outputFolder); if (manifest == null) { throw new DocfxException($"Post processor {postProcessor.ContractName} should not return null manifest"); } // To make sure post processor won't generate duplicate output files ManifestUtility.RemoveDuplicateOutputFiles(manifest.Files); } } } }
private bool OpenLocalPackageCore(string packagePath) { IPackage package = null; try { var extension = Path.GetExtension(packagePath); if (extension.Equals(Constants.PackageExtension, StringComparison.OrdinalIgnoreCase)) { package = new ZipPackage(packagePath); } else if (extension.Equals(Constants.ManifestExtension, StringComparison.OrdinalIgnoreCase)) { using (var str = ManifestUtility.ReadManifest(packagePath)) { var builder = new PackageBuilder(str, Path.GetDirectoryName(packagePath)); package = builder.Build(); } } if (package != null) { LoadPackage(package, packagePath, PackageType.LocalPackage); return(true); } } catch (Exception ex) { UIServices.Show(ex.Message, MessageLevel.Error); return(false); } return(false); }
private bool OpenLocalPackageCore(string packagePath) { IPackage?package = null; string?tempFile = null; try { tempFile = Path.GetTempFileName(); File.Copy(packagePath, tempFile, overwrite: true); var extension = Path.GetExtension(packagePath); if (Constants.PackageExtension.Equals(extension, StringComparison.OrdinalIgnoreCase) || Constants.SymbolPackageExtension.Equals(extension, StringComparison.OrdinalIgnoreCase)) { DiagnosticsClient.TrackPageView("View Existing Package"); #pragma warning disable CA2000 // Dispose objects before losing scope package = new ZipPackage(tempFile); #pragma warning restore CA2000 // Dispose objects before losing scope } else if (Constants.ManifestExtension.Equals(extension, StringComparison.OrdinalIgnoreCase)) { DiagnosticsClient.TrackPageView("View Nuspec"); using var str = ManifestUtility.ReadManifest(tempFile); var builder = new PackageBuilder(str, Path.GetDirectoryName(packagePath)); package = builder.Build(); } if (package != null) { LoadPackage(package, packagePath, packagePath, PackageType.LocalPackage); _tempFile = tempFile; return(true); } } catch (Exception ex) { package?.Dispose(); package = null; UIServices.Show(ex.Message, MessageLevel.Error); return(false); } finally { if (package == null && tempFile != null && File.Exists(tempFile)) { try { File.Delete(tempFile); } catch { /* ignore */ } } } return(false); }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value == null) { return(string.Empty); } var dependency = (PackageDependency)value; return($"{dependency.Id} {ManifestUtility.ReplaceMetadataWithToken(dependency.VersionRange.PrettyPrint())}"); }
private bool OpenLocalPackageCore(string packagePath) { IPackage package = null; string tempFile = null; try { tempFile = Path.GetTempFileName(); File.Copy(packagePath, tempFile, overwrite: true); var extension = Path.GetExtension(packagePath); if (extension.Equals(Constants.PackageExtension, StringComparison.OrdinalIgnoreCase) || extension.Equals(Constants.SymbolPackageExtension, StringComparison.OrdinalIgnoreCase)) { package = new ZipPackage(tempFile); } else if (extension.Equals(Constants.ManifestExtension, StringComparison.OrdinalIgnoreCase)) { using (var str = ManifestUtility.ReadManifest(tempFile)) { var builder = new PackageBuilder(str, Path.GetDirectoryName(packagePath)); package = builder.Build(); } } if (package != null) { LoadPackage(package, packagePath, PackageType.LocalPackage); _tempFile = tempFile; return(true); } } catch (Exception ex) { package = null; UIServices.Show(ex.Message, MessageLevel.Error); return(false); } finally { if (package == null && tempFile != null && File.Exists(tempFile)) { try { File.Delete(tempFile); } catch { /* ignore */ } } } return(false); }
internal void ExportManifest(string fullpath, bool askForConfirmation = true, bool includeFilesSection = true) { if (File.Exists(fullpath) && askForConfirmation) { var confirmed = UIServices.Confirm( Resources.ConfirmToReplaceFile_Title, string.Format(CultureInfo.CurrentCulture, Resources.ConfirmToReplaceFile, fullpath)); if (!confirmed) { return; } } var rootPath = Path.GetDirectoryName(fullpath); using (Stream fileStream = File.Create(fullpath)) { var manifest = Manifest.Create(PackageMetadata); if (includeFilesSection) { var tempPath = Path.GetTempPath(); manifest.Files.AddRange(RootFolder.GetFiles().Select( f => new ManifestFile { Source = string.IsNullOrEmpty(f.OriginalPath()) || f.OriginalPath().StartsWith(tempPath, StringComparison.OrdinalIgnoreCase) ? f.Path : PathUtility.RelativePathTo(rootPath, f.OriginalPath()), Target = f.Path }) ); } using (var ms = new MemoryStream()) { try { manifest.Save(ms); ms.Position = 0; ManifestUtility.SaveToStream(ms, fileStream); } catch (Exception e) { UIServices.Show(e.Message, MessageLevel.Error); } } } }
public object?ConvertBack(object value, Type targetType, object parameter, _CultureInfo culture) { var stringValue = (string?)value; if (string.IsNullOrWhiteSpace(stringValue)) { return(null); } else { stringValue = ManifestUtility.ReplaceTokenWithMetadata(stringValue); if (NuGetVersion.TryParse(stringValue, out var version)) { return(version); } else { return(DependencyProperty.UnsetValue); } } }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var stringValue = (string)value; if (String.IsNullOrEmpty(stringValue)) { return(null); } else { stringValue = ManifestUtility.ReplaceTokenWithMetadata(stringValue); if (VersionRange.TryParse(stringValue, out VersionRange versionSpec)) { return(versionSpec); } else { return(DependencyProperty.UnsetValue); } } }
public object?Convert(object value, Type targetType, object parameter, _CultureInfo culture) { var version = value as NuGetVersion; return(ManifestUtility.ReplaceMetadataWithToken(version?.ToFullString())); }
public void Build(IList <DocumentBuildParameters> parameters, string outputDirectory) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (parameters.Count == 0) { throw new ArgumentException("Parameters are empty.", nameof(parameters)); } var markdownServiceProvider = CompositionContainer.GetExport <IMarkdownServiceProvider>(_container, parameters[0].MarkdownEngineName); if (markdownServiceProvider == null) { Logger.LogError($"Unable to find markdown engine: {parameters[0].MarkdownEngineName}"); throw new DocfxException($"Unable to find markdown engine: {parameters[0].MarkdownEngineName}"); } Logger.LogInfo($"Markdown engine is {parameters[0].MarkdownEngineName}"); var logCodesLogListener = new LogCodesLogListener(); Logger.RegisterListener(logCodesLogListener); // Load schema driven processor from template var sdps = LoadSchemaDrivenDocumentProcessors(parameters[0]).ToList(); if (sdps.Count > 0) { Logger.LogInfo($"{sdps.Count()} schema driven document processor plug-in(s) loaded."); Processors = Processors.Union(sdps); } BuildInfo lastBuildInfo = null; var currentBuildInfo = new BuildInfo { BuildStartTime = DateTime.UtcNow, DocfxVersion = EnvironmentContext.Version, }; try { lastBuildInfo = BuildInfo.Load(_intermediateFolder, true); currentBuildInfo.CommitFromSHA = _commitFromSHA; currentBuildInfo.CommitToSHA = _commitToSHA; if (_intermediateFolder != null) { currentBuildInfo.PluginHash = ComputePluginHash(_assemblyList); currentBuildInfo.TemplateHash = _templateHash; if (!_cleanupCacheHistory && lastBuildInfo != null) { // Reuse the directory for last incremental if cleanup is disabled currentBuildInfo.DirectoryName = lastBuildInfo.DirectoryName; } else { currentBuildInfo.DirectoryName = IncrementalUtility.CreateRandomDirectory(Environment.ExpandEnvironmentVariables(_intermediateFolder)); } } _postProcessorsManager.IncrementalInitialize(_intermediateFolder, currentBuildInfo, lastBuildInfo, parameters[0].ForcePostProcess, parameters[0].MaxParallelism); var manifests = new List <Manifest>(); bool transformDocument = false; if (parameters.All(p => p.Files.Count == 0)) { Logger.LogWarning( $"No file found, nothing will be generated. Please make sure docfx.json is correctly configured.", code: WarningCodes.Build.EmptyInputFiles); } var noContentFound = true; var emptyContentGroups = new List <string>(); foreach (var parameter in parameters) { if (parameter.CustomLinkResolver != null) { if (_container.TryGetExport(parameter.CustomLinkResolver, out ICustomHrefGenerator chg)) { parameter.ApplyTemplateSettings.HrefGenerator = chg; } else { Logger.LogWarning($"Custom href generator({parameter.CustomLinkResolver}) is not found."); } } FileAbstractLayerBuilder falBuilder; if (_intermediateFolder == null) { falBuilder = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(EnvironmentContext.BaseDirectory) .WriteToRealFileSystem(parameter.OutputBaseDir); } else { falBuilder = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(EnvironmentContext.BaseDirectory) .WriteToLink(Path.Combine(_intermediateFolder, currentBuildInfo.DirectoryName)); } if (!string.IsNullOrEmpty(parameter.FALName)) { if (_container.TryGetExport <IInputFileAbstractLayerBuilderProvider>( parameter.FALName, out var provider)) { falBuilder = provider.Create(falBuilder, parameter); } else { Logger.LogWarning($"Input fal builder provider not found, name: {parameter.FALName}."); } } EnvironmentContext.FileAbstractLayerImpl = falBuilder.Create(); if (parameter.ApplyTemplateSettings.TransformDocument) { transformDocument = true; } if (parameter.Files.Count == 0) { manifests.Add(new Manifest()); } else { if (!parameter.Files.EnumerateFiles().Any(s => s.Type == DocumentType.Article)) { if (!string.IsNullOrEmpty(parameter.GroupInfo?.Name)) { emptyContentGroups.Add(parameter.GroupInfo.Name); } } else { noContentFound = false; } parameter.Metadata = _postProcessorsManager.PrepareMetadata(parameter.Metadata); if (!string.IsNullOrEmpty(parameter.VersionName)) { Logger.LogInfo($"Start building for version: {parameter.VersionName}"); } using (new LoggerPhaseScope("BuildCore")) { manifests.Add(BuildCore(parameter, markdownServiceProvider, currentBuildInfo, lastBuildInfo)); } } } if (noContentFound) { Logger.LogWarning( $"No content file found. Please make sure the content section of docfx.json is correctly configured.", code: WarningCodes.Build.EmptyInputContents); } else if (emptyContentGroups.Count > 0) { Logger.LogWarning( $"No content file found in group: {string.Join(",", emptyContentGroups)}. Please make sure the content section of docfx.json is correctly configured.", code: WarningCodes.Build.EmptyInputContents); } using (new LoggerPhaseScope("Postprocess", LogLevel.Verbose)) { var generatedManifest = ManifestUtility.MergeManifest(manifests); generatedManifest.SitemapOptions = parameters.FirstOrDefault()?.SitemapOptions; ManifestUtility.RemoveDuplicateOutputFiles(generatedManifest.Files); ManifestUtility.ApplyLogCodes(generatedManifest.Files, logCodesLogListener.Codes); EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromManifest(generatedManifest, parameters[0].OutputBaseDir) .WriteToManifest(generatedManifest, parameters[0].OutputBaseDir) .Create(); using (new PerformanceScope("Process")) { _postProcessorsManager.Process(generatedManifest, outputDirectory); } using (new PerformanceScope("Dereference")) { if (parameters[0].KeepFileLink) { var count = (from f in generatedManifest.Files from o in f.OutputFiles select o.Value into v where v.LinkToPath != null select v).Count(); if (count > 0) { Logger.LogInfo($"Skip dereferencing {count} files."); } } else { generatedManifest.Dereference(parameters[0].OutputBaseDir, parameters[0].MaxParallelism); } } using (new PerformanceScope("SaveManifest")) { // Save to manifest.json EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(parameters[0].OutputBaseDir) .WriteToRealFileSystem(parameters[0].OutputBaseDir) .Create(); SaveManifest(generatedManifest); } using (new PerformanceScope("Cleanup")) { EnvironmentContext.FileAbstractLayerImpl = null; // overwrite intermediate cache files if (_intermediateFolder != null && transformDocument) { try { currentBuildInfo.IsValid = Logger.WarningCount < Logger.WarningThrottling; currentBuildInfo.Save(_intermediateFolder); if (_cleanupCacheHistory) { ClearCacheExcept(currentBuildInfo.DirectoryName); } } catch (Exception ex) { Logger.LogWarning($"Error happened while saving cache. Message: {ex.Message}."); } } } } } catch { // Leave cache folder there as it contains historical data // exceptions happens in this build does not corrupt the cache theoretically // however the cache file created by this build will never be cleaned up with DisableIncrementalFolderCleanup option if (_intermediateFolder != null && _cleanupCacheHistory) { ClearCacheExcept(lastBuildInfo?.DirectoryName); } throw; } finally { Logger.UnregisterListener(logCodesLogListener); } }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var versionSpec = (VersionRange)value; return(versionSpec == null ? null : ManifestUtility.ReplaceMetadataWithToken(versionSpec.ToShortString())); }
public void Build(IList <DocumentBuildParameters> parameters, string outputDirectory) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (parameters.Count == 0) { throw new ArgumentException("Parameters are empty.", nameof(parameters)); } var markdownServiceProvider = CompositionUtility.GetExport <IMarkdownServiceProvider>(_container, parameters[0].MarkdownEngineName); if (markdownServiceProvider == null) { Logger.LogError($"Unable to find markdown engine: {parameters[0].MarkdownEngineName}"); throw new DocfxException($"Unable to find markdown engine: {parameters[0].MarkdownEngineName}"); } Logger.LogInfo($"Markdown engine is {parameters[0].MarkdownEngineName}"); _postProcessorsManager.IncrementalInitialize(_intermediateFolder, _currentBuildInfo, _lastBuildInfo, parameters[0].ForcePostProcess); var manifests = new List <Manifest>(); bool transformDocument = false; foreach (var parameter in parameters) { if (parameter.CustomLinkResolver != null) { ICustomHrefGenerator chg; if (_container.TryGetExport(parameter.CustomLinkResolver, out chg)) { parameter.ApplyTemplateSettings.HrefGenerator = chg; } else { Logger.LogWarning($"Custom href generator({parameter.CustomLinkResolver}) is not found."); } } EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(EnvironmentContext.BaseDirectory) .WriteToRealFileSystem(parameter.OutputBaseDir) .Create(); if (parameter.Files.Count == 0) { Logger.LogWarning(string.IsNullOrEmpty(parameter.VersionName) ? "No files found, nothing is generated in default version." : $"No files found, nothing is generated in version \"{parameter.VersionName}\"."); manifests.Add(new Manifest()); continue; } if (parameter.ApplyTemplateSettings.TransformDocument) { transformDocument = true; } parameter.Metadata = _postProcessorsManager.PrepareMetadata(parameter.Metadata); if (!string.IsNullOrEmpty(parameter.VersionName)) { Logger.LogInfo($"Start building for version: {parameter.VersionName}"); } manifests.Add(BuildCore(parameter, markdownServiceProvider)); } EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(parameters[0].OutputBaseDir) .WriteToRealFileSystem(parameters[0].OutputBaseDir) .Create(); var generatedManifest = ManifestUtility.MergeManifest(manifests); ManifestUtility.RemoveDuplicateOutputFiles(generatedManifest.Files); using (new PerformanceScope("Process")) { _postProcessorsManager.Process(generatedManifest, outputDirectory); } using (new PerformanceScope("SaveManifest")) { // Save to manifest.json EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(parameters[0].OutputBaseDir) .WriteToRealFileSystem(parameters[0].OutputBaseDir) .Create(); SaveManifest(generatedManifest); } using (new PerformanceScope("Cleanup")) { EnvironmentContext.FileAbstractLayerImpl = null; // overwrite intermediate cache files if (_intermediateFolder != null && transformDocument) { _currentBuildInfo.Save(_intermediateFolder); if (_lastBuildInfo != null) { Directory.Delete(Path.Combine(Environment.ExpandEnvironmentVariables(_intermediateFolder), _lastBuildInfo.DirectoryName), true); } } } }
public void Build(IList <DocumentBuildParameters> parameters, string outputDirectory) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (parameters.Count == 0) { throw new ArgumentException("Parameters are empty.", nameof(parameters)); } var markdownServiceProvider = CompositionContainer.GetExport <IMarkdownServiceProvider>(_container, parameters[0].MarkdownEngineName); if (markdownServiceProvider == null) { Logger.LogError($"Unable to find markdown engine: {parameters[0].MarkdownEngineName}"); throw new DocfxException($"Unable to find markdown engine: {parameters[0].MarkdownEngineName}"); } Logger.LogInfo($"Markdown engine is {parameters[0].MarkdownEngineName}"); var logCodesLogListener = new LogCodesLogListener(); Logger.RegisterListener(logCodesLogListener); try { _postProcessorsManager.IncrementalInitialize(_intermediateFolder, _currentBuildInfo, _lastBuildInfo, parameters[0].ForcePostProcess, parameters[0].MaxParallelism); var manifests = new List <Manifest>(); bool transformDocument = false; foreach (var parameter in parameters) { if (parameter.CustomLinkResolver != null) { if (_container.TryGetExport(parameter.CustomLinkResolver, out ICustomHrefGenerator chg)) { parameter.ApplyTemplateSettings.HrefGenerator = chg; } else { Logger.LogWarning($"Custom href generator({parameter.CustomLinkResolver}) is not found."); } } if (_intermediateFolder == null) { EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(EnvironmentContext.BaseDirectory) .WriteToRealFileSystem(parameter.OutputBaseDir) .Create(); } else { EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(EnvironmentContext.BaseDirectory) .WriteToLink(Path.Combine(_intermediateFolder, _currentBuildInfo.DirectoryName)) .Create(); } if (parameter.ApplyTemplateSettings.TransformDocument) { transformDocument = true; } if (parameter.Files.Count == 0) { Logger.LogWarning(string.IsNullOrEmpty(parameter.VersionName) ? "No files found, nothing is generated in default version." : $"No files found, nothing is generated in version \"{parameter.VersionName}\"."); manifests.Add(new Manifest()); continue; } parameter.Metadata = _postProcessorsManager.PrepareMetadata(parameter.Metadata); if (!string.IsNullOrEmpty(parameter.VersionName)) { Logger.LogInfo($"Start building for version: {parameter.VersionName}"); } manifests.Add(BuildCore(parameter, markdownServiceProvider)); } using (new LoggerPhaseScope("Postprocess", LogLevel.Verbose)) { var generatedManifest = ManifestUtility.MergeManifest(manifests); ManifestUtility.RemoveDuplicateOutputFiles(generatedManifest.Files); ManifestUtility.ApplyLogCodes(generatedManifest.Files, logCodesLogListener.Codes); EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromManifest(generatedManifest, parameters[0].OutputBaseDir) .WriteToManifest(generatedManifest, parameters[0].OutputBaseDir) .Create(); using (new PerformanceScope("Process")) { _postProcessorsManager.Process(generatedManifest, outputDirectory); } using (new PerformanceScope("Dereference")) { if (parameters[0].KeepFileLink) { var count = (from f in generatedManifest.Files from o in f.OutputFiles select o.Value into v where v.LinkToPath != null select v).Count(); if (count > 0) { Logger.LogInfo($"Skip dereferencing {count} files."); } } else { generatedManifest.Dereference(parameters[0].OutputBaseDir, parameters[0].MaxParallelism); } } using (new PerformanceScope("SaveManifest")) { // Save to manifest.json EnvironmentContext.FileAbstractLayerImpl = FileAbstractLayerBuilder.Default .ReadFromRealFileSystem(parameters[0].OutputBaseDir) .WriteToRealFileSystem(parameters[0].OutputBaseDir) .Create(); SaveManifest(generatedManifest); } using (new PerformanceScope("Cleanup")) { EnvironmentContext.FileAbstractLayerImpl = null; // overwrite intermediate cache files if (_intermediateFolder != null && transformDocument) { try { _currentBuildInfo.Save(_intermediateFolder); if (_lastBuildInfo != null) { ClearCacheWithNoThrow(_lastBuildInfo.DirectoryName, true); } } catch (Exception ex) { Logger.LogWarning($"Error happened while saving cache. Message: {ex.Message}."); } } } } } catch (Exception) { if (_intermediateFolder != null) { ClearCacheWithNoThrow(_currentBuildInfo.DirectoryName, true); } throw; } finally { Logger.UnregisterListener(logCodesLogListener); } }
/// <summary> /// 1. Retrive <a href=''></a> from each html. /// 2. Foreach link, try to fix it. /// 2.1 If the link is full path, just keep it. /// 2.2 If the link is root path(/a/b), just add host in prefix. /// 2.3 If the link is relative path(a/b.html) /// 2.3.1 If the link in TOC, just keep it. /// 2.3.2 If the link NOT in TOC and in Manifest, try to get the canonical url. /// 2.3.3 If the link NOT in TOC and NOT in Manifest, log warning to the invalid link. /// 2.4 Others, keep it as the origin. /// </summary> /// <param name="htmlFilePaths">The htmls' relative path in TOC.</param> public void Transform(IEnumerable <string> htmlFilePaths) { Guard.ArgumentNotNull(htmlFilePaths, nameof(htmlFilePaths)); var tocUrlCache = new UrlCache(_basePath, htmlFilePaths); Parallel.ForEach( htmlFilePaths, htmlFilePath => { var doc = new HtmlDocument(); var currentHtml = PdfHelper.NormalizeFileLocalPath(_basePath, htmlFilePath, false); if (!File.Exists(currentHtml)) { return; } try { var baseDirectory = Path.GetDirectoryName(currentHtml); doc.Load(currentHtml); var tags = doc.DocumentNode.SelectNodes("//a[@href]"); if (tags != null && tags.Count > 0) { bool isTransformed = false; foreach (var tag in tags) { var src = tag.Attributes["href"].Value; Uri uri; if (Uri.TryCreate(src, UriKind.Relative, out uri)) { try { if (Path.IsPathRooted(src)) { if (string.IsNullOrEmpty(_pdfOptions.Host)) { Logger.LogVerbose($"No host passed, so just keep the url as origin: {src}.", htmlFilePath); continue; } Uri host; if (Uri.TryCreate(_pdfOptions.Host, UriKind.Absolute, out host)) { tag.Attributes["href"].Value = new Uri(host, uri.OriginalString).ToString(); isTransformed = true; } else { Logger.LogVerbose($"The host format:{_pdfOptions.Host} is invalid, so just keep the url as origin: {src}.", htmlFilePath); } } else { // uri.OriginalString may be "virtual-machines-windows.html#abc?toc=%2fazure%2fvirtual-machines%2fwindows%2ftoc.json",then we cannot find the file, so just remove the querystring. var withoutQueryString = uri.OriginalString.RemoveUrlQueryString(); if (uri.OriginalString != withoutQueryString) { tag.Attributes["href"].Value = withoutQueryString; isTransformed = true; } // originalString is used to find the file, so need to remove querystring and bookmark var originalString = uri.OriginalString.RemoveUrlQueryString().RemoveUrlBookmark(); // because when publish to website the url path is toLower so use OrdinalIgnoreCase. string srcInCurrentHtml = new Uri(Path.Combine(baseDirectory, originalString)).LocalPath?.ToLower(); if (originalString.EndsWith(BuildToolConstants.OutputFileExtensions.ContentHtmlExtension, StringComparison.OrdinalIgnoreCase) && !tocUrlCache.Contains(srcInCurrentHtml)) { var conceptual = _manifestUrlCache.Query(srcInCurrentHtml); var assetId = ManifestUtility.GetAssetId(conceptual); if (conceptual == null) { Logger.LogWarning($"Can not find the relative path: {uri.OriginalString} in manifest. So skip to fix the invalid link.", htmlFilePath); continue; } if (!string.IsNullOrEmpty(_pdfOptions.Locale) && !string.IsNullOrEmpty(_pdfOptions.Host)) { // the assetId may has '.html' extension, but we should redirect to the site which should not have '.html' extension, so trim it here. tag.Attributes["href"].Value = string.Format(_pdfOptions.ExternalLinkFormat, assetId.TrimEnd(BuildToolConstants.OutputFileExtensions.ContentHtmlExtension)); isTransformed = true; } else { Logger.LogVerbose($"Host/Locale is null or empty, so just skip to keep the it as origin: {uri.OriginalString}.", htmlFilePath); } } } } catch (Exception ex) { Logger.LogWarning(ex.Message, htmlFilePath); } } } if (isTransformed) { doc.Save(currentHtml); } } } catch (Exception ex) { Logger.LogWarning($"Transfer html not in toc error, details: {ex.Message}", htmlFilePath); } }); }
public override string ToString() { return(Id + "." + ManifestUtility.ReplaceMetadataWithToken(Version.ToFullString())); }