Skip to content

Commit

Permalink
fix: support load plugins from template (dotnet#8812)
Browse files Browse the repository at this point in the history
fix: load plugins from template
  • Loading branch information
yufeih authored and p-kostov committed Jun 28, 2024
1 parent 384e1a1 commit 15bb1d5
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,14 @@ Goal and limitation

Preparation
-----------
1. Create a new C# class library project in `Visual Studio`, targets .NET Framework 4.7.2 or later.
1. Create a new C# class library targeting `net6.0` or later.

2. Add nuget packages:
* `System.Collections.Immutable` with version 1.3.1 or later (if not already included in your .NET Framework target version)
* `Microsoft.Composition` with version 1.0.31
2. Add NuGet package reference to `System.Composition`, `Microsoft.DocAsCode.Plugins` and `Microsoft.DocAsCode.Common`.

3. Add `Microsoft.DocAsCode.Plugins` and `Microsoft.DocAsCode.Common`
If building DocFX from source code then add a reference to the project,
otherwise add the nuget packages with the same version as DocFX.

4. Add framework assembly references:
`PresentationCore`, `PresentationFramework`, `WindowsBase`. (This step is optional in Visual Studio 2017 or above)

5. Add a project for converting rtf to html:
4. Add a project for converting rtf to html:
Clone project [MarkupConverter](https://github.com/mmanela/MarkupConverter), and reference it.

6. Copy the code file `CSharp/parallel/ParallelExtensionsExtras/TaskSchedulers/StaTaskScheduler.cs` from [DotNet Samples](https://github.com/dotnet/samples)
5. Copy the code file `CSharp/parallel/ParallelExtensionsExtras/TaskSchedulers/StaTaskScheduler.cs` from [DotNet Samples](https://github.com/dotnet/samples)

Create a document processor
---------------------------
Expand Down Expand Up @@ -137,10 +128,10 @@ Enable plug-in
--------------
1. Build our project.
2. Copy the output dll files to:
* Global: a folder you create, named `Plugins` under the folder where the Docfx executable resides.
* Non-global: a folder you create with the name `Plugins` under a template folder. Then run `DocFX build` command with parameter `-t {template}`.
* Global: the Docfx executable directory.
* Non-global: a folder you create with the name `plugins` under a template folder. Then run `DocFX build` command with parameter `-t {template}`.

*Hint*: DocFX can merge templates so create a template that only contains the `Plugins` folder, then run the command `DocFX build` with parameter `-t {templateForRender},{templateForPlugins}`.
*Hint*: DocFX can merge templates so create a template that only contains the `plugins` folder, then run the command `DocFX build` with parameter `-t {templateForRender},{templateForPlugins}`.

Build document
--------------
Expand Down
33 changes: 5 additions & 28 deletions src/Microsoft.DocAsCode.App/Helpers/DocumentBuilderWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Microsoft.DocAsCode.Build.ConceptualDocuments;
using Microsoft.DocAsCode.Build.Engine;
using Microsoft.DocAsCode.Build.ManagedReference;
using Microsoft.DocAsCode.Build.ResourceFiles;
using Microsoft.DocAsCode.Build.RestApi;
using Microsoft.DocAsCode.Build.SchemaDriven;
using Microsoft.DocAsCode.Build.TableOfContents;
using Microsoft.DocAsCode.Build.UniversalReference;
using Microsoft.DocAsCode.Common;
using Microsoft.DocAsCode.Plugins;

Expand Down Expand Up @@ -42,7 +35,9 @@ public static void BuildDocument(BuildJsonConfig config, BuildOptions options, T
postProcessorNames = postProcessorNames.Add("SitemapGenerator");
}

using var builder = new DocumentBuilder(s_pluginAssemblies, postProcessorNames);
var pluginAssemblies = templateManager.GetTemplateDirectories().Select(d => Path.Combine(d, "plugins")).SelectMany(LoadPluginAssemblies);

using var builder = new DocumentBuilder(s_pluginAssemblies.Concat(pluginAssemblies), postProcessorNames);
using (new PerformanceScope("building documents", LogLevel.Info))
{
var parameters = ConfigToParameter(config, options, templateManager, baseDirectory, outputDirectory, templateDirectory);
Expand All @@ -52,20 +47,8 @@ public static void BuildDocument(BuildJsonConfig config, BuildOptions options, T

private static IEnumerable<Assembly> LoadPluginAssemblies(string pluginDirectory)
{
var defaultPluggedAssemblies = new List<Assembly>
{
typeof(ConceptualDocumentProcessor).Assembly,
typeof(ManagedReferenceDocumentProcessor).Assembly,
typeof(ResourceDocumentProcessor).Assembly,
typeof(RestApiDocumentProcessor).Assembly,
typeof(TocDocumentProcessor).Assembly,
typeof(SchemaDrivenDocumentProcessor).Assembly,
typeof(UniversalReferenceDocumentProcessor).Assembly,
};
foreach (var assem in defaultPluggedAssemblies)
{
yield return assem;
}
if (!Directory.Exists(pluginDirectory))
yield break;

Logger.LogInfo($"Searching custom plugins in directory {pluginDirectory}...");

Expand All @@ -88,12 +71,6 @@ private static IEnumerable<Assembly> LoadPluginAssemblies(string pluginDirectory
continue;
}

if (defaultPluggedAssemblies.Select(n => n.GetName().Name).Contains(assemblyName))
{
Logger.LogVerbose($"Skipping default plugged assembly: {assemblyName}.");
continue;
}

if (!IsDocfxPluginAssembly(assemblyFile))
{
Logger.LogVerbose($"Skipping non-plugin assembly: {assemblyName}.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,29 @@ public TemplateProcessor GetTemplateProcessor(DocumentBuildContext context, int

private CompositeResourceReader CreateTemplateResource(IEnumerable<string> resources)
{
return new(resources.Select(FindResource).Where(s => s != null));
return new(GetTemplateDirectories(resources).Select(path => new LocalFileResourceReader(path)));
}

public IEnumerable<string> GetTemplateDirectories()
{
return GetTemplateDirectories(_templates);
}

ResourceFileReader? FindResource(string name)
private IEnumerable<string> GetTemplateDirectories(IEnumerable<string> names)
{
foreach (var name in names)
{
var directory = Path.Combine(AppContext.BaseDirectory, "templates", name);
var directory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "templates", name));
if (Directory.Exists(directory))
{
return new LocalFileResourceReader(directory);
yield return directory;
}

directory = Path.Combine(_baseDirectory, name);
directory = Path.GetFullPath(Path.Combine(_baseDirectory, name));
if (Directory.Exists(directory))
{
return new LocalFileResourceReader(directory);
yield return directory;
}

return null;
}
}

Expand Down
15 changes: 15 additions & 0 deletions test/docfx.Tests/Assets/template/plugins/CustomPostProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Immutable;
using System.Composition;
using Microsoft.DocAsCode.Plugins;

[Export(nameof(CustomPostProcessor), typeof(IPostProcessor))]
public class CustomPostProcessor : IPostProcessor
{
public ImmutableDictionary<string, object> PrepareMetadata(ImmutableDictionary<string, object> metadata) => metadata;

public Manifest Process(Manifest manifest, string outputFolder)
{
File.WriteAllText(Path.Combine(outputFolder, "customPostProcessor.txt"), "customPostProcessor");
return manifest;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<Project></Project>
19 changes: 19 additions & 0 deletions test/docfx.Tests/Assets/template/plugins/plugins.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.DocAsCode.Plugins\Microsoft.DocAsCode.Plugins.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Composition" />
</ItemGroup>

</Project>
Binary file not shown.
115 changes: 61 additions & 54 deletions test/docfx.Tests/CompositeCommandTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,61 +31,66 @@ public CompositeCommandTest()
public void TestCommandFromCSCodeToHtml()
{
// Create source file
var sourceCode = @"
namespace Hello{
/// <summary>
/// The class &lt; &gt; > description goes here...
/// </summary>
/// <example>
/// Here is some &lt; encoded &gt; example...
/// > [!NOTE]
/// > This is *note*
///
/// <code>
/// var handler = DateTimeHandler();
/// for (var i = 0; i &lt; 10; i++){
/// date = date.AddMonths(1);
/// }
/// </code>
/// </example>
public class HelloWorld {}}
";
var sourceCode = """
namespace Hello{
/// <summary>
/// The class &lt; &gt; > description goes here...
/// </summary>
/// <example>
/// Here is some &lt; encoded &gt; example...
/// > [!NOTE]
/// > This is *note*
///
/// <code>
/// var handler = DateTimeHandler();
/// for (var i = 0; i &lt; 10; i++){
/// date = date.AddMonths(1);
/// }
/// </code>
/// </example>
public class HelloWorld {}}
""";
var sourceFile = Path.Combine(_projectFolder, "src", "test.cs");
CreateFile(sourceFile, sourceCode, "src");

var docfxJson = $@"{{
""metadata"": [
{{
""src"": ""src/test.cs"",
""dest"": ""api""
}}
],
""build"": {{
""content"": {{
""files"": ""api/*.yml""
}},
""dest"": ""{_outputFolder.ToNormalizedPath()}/site"",
""sitemap"":{{
""baseUrl"": ""https://dotnet.github.io/docfx"",
""priority"": 0.1,
""changefreq"": ""monthly"",
""fileOptions"":{{
""**.yml"": {{
""priority"": 0.3,
""lastmod"": ""1999-01-01""
}},
""**/Hello.yml"": {{
""baseUrl"": ""https://dotnet.github.io/docfx/1"",
""priority"": 0.8,
""changefreq"": ""Daily""
}}
}}
}}
}}
}}";
var docfxJson = $$"""
{
"metadata": [
{
"src": "src/test.cs",
"dest": "api"
}
],
"build": {
"content": {
"files": "api/*.yml"
},
"dest": "{{_outputFolder.ToNormalizedPath()}}/site",
"sitemap":{
"baseUrl": "https://dotnet.github.io/docfx",
"priority": 0.1,
"changefreq": "monthly",
"fileOptions":{
"**.yml": {
"priority": 0.3,
"lastmod": "1999-01-01"
},
"**/Hello.yml": {
"baseUrl": "https://dotnet.github.io/docfx/1",
"priority": 0.8,
"changefreq": "Daily"
}
}
}
}
}
""";

var docfxJsonFile = Path.Combine(_projectFolder, "docfx.json");
File.WriteAllText(docfxJsonFile, docfxJson);
Program.Main(new string[] { docfxJsonFile });
Assert.Equal(0, Program.Main(new string[] { docfxJsonFile }));
var filePath = Path.Combine(_outputFolder, "site", "api", "Hello.HelloWorld.html");
Assert.True(File.Exists(filePath));
var html = new HtmlDocument();
Expand All @@ -95,10 +100,12 @@ public class HelloWorld {}}
var note = html.DocumentNode.SelectSingleNode("//div[@class='NOTE']").InnerHtml;
Assert.Equal("<h5>Note</h5>\n<p>This is <em>note</em></p>", note.Trim());
var code = html.DocumentNode.SelectNodes("//pre/code")[1].InnerHtml;
Assert.Equal(@"var handler = DateTimeHandler();
for (var i = 0; i &lt; 10; i++){
date = date.AddMonths(1);
}".Replace("\r\n", "\n"), code);
Assert.Equal("""
var handler = DateTimeHandler();
for (var i = 0; i &lt; 10; i++){
date = date.AddMonths(1);
}
""".Replace("\r\n", "\n"), code);
var sitemap = Path.Combine(_outputFolder, "site", "sitemap.xml");
Assert.True(File.Exists(sitemap));

Expand Down
22 changes: 22 additions & 0 deletions test/docfx.Tests/DocsetTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,26 @@ public static async Task CustomLogo_Override_LogoFromTemplate()

Assert.Equal("<svg>my svg</svg>", outputs["logo.svg"]());
}

[Fact]
public static async Task Load_Custom_Plugin_From_Template()
{
var outputs = await Build(new()
{
["docfx.json"] =
"""
{
"build": {
"content": [{ "files": [ "*.md" ] }],
"template": ["default", "../../Assets/template"],
"dest": "_site",
"postProcessors": ["CustomPostProcessor"]
}
}
""",
["index.md"] = ""
});

Assert.Equal("customPostProcessor", outputs["customPostProcessor.txt"]());
}
}
2 changes: 0 additions & 2 deletions test/docfx.Tests/PdfTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime.CompilerServices;

using Microsoft.DocAsCode.Tests.Common;

using Xunit;

namespace Microsoft.DocAsCode.Tests;
Expand Down

0 comments on commit 15bb1d5

Please sign in to comment.