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);
                }
            }
        }
예제 #2
0
        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);
                    }
                }
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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())}");
        }
예제 #6
0
        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);
        }
예제 #7
0
        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);
                    }
                }
            }
        }
예제 #8
0
        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);
                }
            }
        }
예제 #9
0
        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);
                }
            }
        }
예제 #10
0
        public object?Convert(object value, Type targetType, object parameter, _CultureInfo culture)
        {
            var version = value as NuGetVersion;

            return(ManifestUtility.ReplaceMetadataWithToken(version?.ToFullString()));
        }
예제 #11
0
        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);
            }
        }
예제 #12
0
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var versionSpec = (VersionRange)value;

            return(versionSpec == null ? null : ManifestUtility.ReplaceMetadataWithToken(versionSpec.ToShortString()));
        }
예제 #13
0
        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);
                    }
                }
            }
        }
예제 #14
0
        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);
            }
        }
예제 #15
0
        /// <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()));
 }