From b33bee9ad5e5a81308339104a2c9c8b59bc1e583 Mon Sep 17 00:00:00 2001 From: dvolper Date: Fri, 3 May 2024 22:17:01 +0200 Subject: [PATCH] output loading --- .../Commands/GenerateCommand.Outputs.cs | 33 ++++++------------- .../Commands/GenerateCommand.cs | 22 ++++++++++--- .../DokiOutputAttribute.cs | 2 ++ .../ClassLibraryOutput.cs | 2 +- src/Doki/DocumentationGenerator.cs | 5 +++ 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/Doki.CommandLine/Commands/GenerateCommand.Outputs.cs b/src/Doki.CommandLine/Commands/GenerateCommand.Outputs.cs index f15e593..d8308b8 100644 --- a/src/Doki.CommandLine/Commands/GenerateCommand.Outputs.cs +++ b/src/Doki.CommandLine/Commands/GenerateCommand.Outputs.cs @@ -12,10 +12,7 @@ namespace Doki.CommandLine.Commands; internal partial class GenerateCommand { - private readonly SourceRepository _nuget = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json"); - private readonly SourceCacheContext _cacheContext = new(); - - private async Task LoadOutputAsync(DirectoryInfo workingDirectory, + private async Task LoadOutputAsync(DirectoryInfo workingDirectory, DokiConfig.DokiConfigOutput output, bool allowPreview, CancellationToken cancellationToken) { var outputContext = new OutputContext(workingDirectory, output.Options); @@ -29,13 +26,13 @@ internal partial class GenerateCommand return fileInfo.Extension.ToLower() switch { - ".csproj" => await LoadOutputFromProjectAsync(fileInfo, output, outputContext, cancellationToken), - ".dll" => LoadOutputFromAssembly(fileInfo.FullName, output, outputContext), + ".csproj" => await LoadOutputFromProjectAsync(fileInfo, output, cancellationToken), + ".dll" => LoadOutputFromAssembly(fileInfo.FullName, output), _ => null }; } - private async Task LoadOutputFromNuGetAsync(DokiConfig.DokiConfigOutput output, + private async Task LoadOutputFromNuGetAsync(DokiConfig.DokiConfigOutput output, OutputContext outputContext, bool allowPreview, CancellationToken cancellationToken) { _logger.LogDebug("Loading output from NuGet: {PackageId}", output.Type); @@ -47,11 +44,11 @@ internal partial class GenerateCommand var assemblyPath = await nugetLoader.LoadPackageAsync(output.Type, nugetFolder, allowPreview, cancellationToken); - return LoadOutputFromAssembly(assemblyPath, output, outputContext); + return LoadOutputFromAssembly(assemblyPath, output); } - private async Task LoadOutputFromProjectAsync(FileInfo fileInfo, DokiConfig.DokiConfigOutput output, - OutputContext outputContext, CancellationToken cancellationToken) + private async Task LoadOutputFromProjectAsync(FileInfo fileInfo, DokiConfig.DokiConfigOutput output, + CancellationToken cancellationToken) { _logger.LogDebug("Loading output from project: {ProjectFileName}", fileInfo.Name); @@ -61,27 +58,17 @@ internal partial class GenerateCommand var assemblyPath = Path.Combine(fileInfo.DirectoryName!, "bin", "Release", "net8.0", $"{fileInfo.Name[..^fileInfo.Extension.Length]}.dll"); - return LoadOutputFromAssembly(assemblyPath, output, outputContext); + return LoadOutputFromAssembly(assemblyPath, output); } - private IOutput? LoadOutputFromAssembly(string path, DokiConfig.DokiConfigOutput output, - OutputContext outputContext) + private Type? LoadOutputFromAssembly(string path, DokiConfig.DokiConfigOutput output) { _logger.LogDebug("Loading output from assembly: {AssemblyPath}", path); var assembly = Assembly.LoadFrom(path); - var outputType = assembly.GetType(output.Type) ?? assembly + return assembly.GetType(output.Type) ?? assembly .GetExportedTypes() .FirstOrDefault(t => t.GetCustomAttribute()?.Name == output.Type); - - // ReSharper disable once InvertIf - if (outputType == null) - { - _logger.LogError("Could not find output type: {OutputType}", output.Type); - return null; - } - - return Activator.CreateInstance(outputType, outputContext) as IOutput; } } \ No newline at end of file diff --git a/src/Doki.CommandLine/Commands/GenerateCommand.cs b/src/Doki.CommandLine/Commands/GenerateCommand.cs index 9ad7cdb..e9c4c97 100644 --- a/src/Doki.CommandLine/Commands/GenerateCommand.cs +++ b/src/Doki.CommandLine/Commands/GenerateCommand.cs @@ -1,8 +1,10 @@ using System.CommandLine; using System.CommandLine.Invocation; using System.Diagnostics; +using System.Reflection; using System.Text.Json; using System.Xml.XPath; +using Doki.Output; using Microsoft.Extensions.FileSystemGlobbing; using Microsoft.Extensions.FileSystemGlobbing.Abstractions; using Microsoft.Extensions.Logging; @@ -207,19 +209,29 @@ private async Task LoadOutputsAsync(GenerateContext context, CancellationTo { if (string.IsNullOrWhiteSpace(output.Type)) { - _logger.LogError("No type configured."); + _logger.LogError("No output type configured."); return -1; } - var instance = await LoadOutputAsync(context.Directory, output, context.AllowPreview, cancellationToken); + var outputType = await LoadOutputAsync(context.Directory, output, context.AllowPreview, cancellationToken); - if (instance == null) + if (outputType == null) { - _logger.LogError("Could not load output."); + _logger.LogError("Could not load output: {OutputType}", output.Type); return -1; } - context.Generator.AddOutput(instance); + _logger.LogDebug("Adding output: {OutputType}", outputType); + + var outputAttribute = outputType.GetCustomAttribute(); + + var methodName = outputAttribute?.Scoped == true + ? nameof(DocumentationGenerator.AddScopedOutput) + : nameof(DocumentationGenerator.AddOutput); + + var genericMethod = typeof(DocumentationGenerator).GetMethod(methodName)!.MakeGenericMethod(outputType); + + genericMethod.Invoke(context.Generator, []); } return 0; diff --git a/src/Doki.Output.Abstractions/DokiOutputAttribute.cs b/src/Doki.Output.Abstractions/DokiOutputAttribute.cs index 0ce39a5..deec201 100644 --- a/src/Doki.Output.Abstractions/DokiOutputAttribute.cs +++ b/src/Doki.Output.Abstractions/DokiOutputAttribute.cs @@ -11,6 +11,8 @@ public sealed class DokiOutputAttribute : Attribute /// public string Name { get; } + public bool Scoped { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/src/Doki.Output.ClassLibrary/ClassLibraryOutput.cs b/src/Doki.Output.ClassLibrary/ClassLibraryOutput.cs index 6432357..c59e9c1 100644 --- a/src/Doki.Output.ClassLibrary/ClassLibraryOutput.cs +++ b/src/Doki.Output.ClassLibrary/ClassLibraryOutput.cs @@ -1,6 +1,6 @@ namespace Doki.Output.ClassLibrary; -[DokiOutput("Doki.Output.ClassLibrary")] +[DokiOutput("Doki.Output.ClassLibrary", Scoped = true)] public sealed class ClassLibraryOutput(OutputContext context) : OutputBase(context) { public override async Task WriteAsync(ContentList contentList, CancellationToken cancellationToken = default) diff --git a/src/Doki/DocumentationGenerator.cs b/src/Doki/DocumentationGenerator.cs index a7d2ba8..a89fcac 100644 --- a/src/Doki/DocumentationGenerator.cs +++ b/src/Doki/DocumentationGenerator.cs @@ -133,6 +133,11 @@ public void AddOutput(IOutput output) _serviceCollection.AddSingleton(typeof(IOutput), output); } + + public void AddOutput() where T : IOutput + { + _serviceCollection.AddSingleton(typeof(IOutput), typeof(T)); + } public void AddScopedOutput() where T : IOutput {