Skip to content

Commit

Permalink
gen assembly metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
vipwan committed Sep 5, 2024
1 parent db97322 commit a77d17d
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 2 deletions.
142 changes: 142 additions & 0 deletions Biwen.AutoClassGen.Gen/AssemblyMetadataGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.Versioning;
using System.Text;

namespace Biwen.AutoClassGen;

/// <summary>
/// 生成程序集元数据
/// </summary>
[Generator]
public class AssemblyMetadataGenerator : IIncrementalGenerator
{
private static readonly HashSet<string> _attributes = [
nameof(AssemblyCompanyAttribute),
nameof(AssemblyConfigurationAttribute),
nameof(AssemblyCopyrightAttribute),
nameof(AssemblyCultureAttribute),
nameof(AssemblyDelaySignAttribute),
nameof(AssemblyDescriptionAttribute),
nameof(AssemblyFileVersionAttribute),
nameof(AssemblyInformationalVersionAttribute),
nameof(AssemblyKeyFileAttribute),
nameof(AssemblyKeyNameAttribute),
nameof(AssemblyMetadataAttribute),
nameof(AssemblyProductAttribute),
nameof(AssemblySignatureKeyAttribute),
nameof(AssemblyTitleAttribute),
nameof(AssemblyTrademarkAttribute),
nameof(AssemblyVersionAttribute),
nameof(NeutralResourcesLanguageAttribute),
nameof(TargetFrameworkAttribute),
"UserSecretsIdAttribute"];

private const string AssemblyVersionAttributeMetadataName = "System.Reflection.AssemblyVersionAttribute";
private const string ONamespace = "build_property.rootnamespace";//命名空间

private readonly record struct AssemblyConstant(string Name, string Value);

public void Initialize(IncrementalGeneratorInitializationContext context)
{
//获取根命名空间
var rootNamespace = context.AnalyzerConfigOptionsProvider.Select((pvd, _) =>
{
pvd.GlobalOptions.TryGetValue(ONamespace, out var @namespace);
return @namespace;
});

//获取程序集元数据
var attrs = context.SyntaxProvider.ForAttributeWithMetadataName(
AssemblyVersionAttributeMetadataName,
(context, _) => context is CompilationUnitSyntax,
(syntaxContext, _) =>
{
var attributes = syntaxContext.TargetSymbol.GetAttributes();
var constants = new List<AssemblyConstant>();

foreach (var attribute in attributes)
{
var name = attribute.AttributeClass?.Name;
if (name == null || !_attributes.Contains(name))
continue;

if (attribute.ConstructorArguments.Length == 1)
{
// remove Assembly
if (name.Length > 8 && name.StartsWith("Assembly", StringComparison.Ordinal))
name = name.Substring(8);

// remove Attribute
if (name.Length > 9)
name = name.Substring(0, name.Length - 9);

var argument = attribute.ConstructorArguments.FirstOrDefault();
var value = argument.ToCSharpString() ?? string.Empty;

if (string.IsNullOrWhiteSpace(value))
continue;

var constant = new AssemblyConstant(name, value);
constants.Add(constant);
}
else if (name == nameof(AssemblyMetadataAttribute) && attribute.ConstructorArguments.Length == 2)
{
var nameArgument = attribute.ConstructorArguments[0];
var key = nameArgument.Value?.ToString() ?? string.Empty;

var valueArgument = attribute.ConstructorArguments[1];
var value = valueArgument.ToCSharpString() ?? string.Empty;

if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value))
continue;

// prevent duplicates
if (constants.Any(c => c.Name == key))
continue;

var constant = new AssemblyConstant(key, value);
constants.Add(constant);
}
}
return constants;
}).Where(c => c?.Count > 0);

//合并数据
var inc = attrs.Combine(rootNamespace);

//生成源代码
context.RegisterSourceOutput(inc, (ctx, info) =>
{
var constants = info.Left;
var rootNamespace = info.Right;

if (string.IsNullOrEmpty(rootNamespace))
return;

var sb = new StringBuilder();
sb.AppendLine("// <auto-generated/>");
sb.AppendLine($"namespace {rootNamespace}.Generated;");
sb.AppendLine();
sb.AppendLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"{ThisAssembly.Product}\", \"{ThisAssembly.FileVersion}\")]");
sb.AppendLine("public static class AssemblyMetadata");
sb.AppendLine("{");
foreach (var constant in constants)
{
sb.AppendLine($"public const string {constant.Name} = {constant.Value};");
}
sb.AppendLine("}");

var source = sb.ToString().FormatContent();

ctx.AddSource("AssemblyMetadata.g.cs", SourceText.From(source, Encoding.UTF8));
});
}
}
4 changes: 2 additions & 2 deletions Biwen.AutoClassGen.Gen/Biwen.AutoClassGen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<AnalysisLevel>6.0-all</AnalysisLevel>
<Authors>万雅虎</Authors>
<PackageVersion>1.3.7.2</PackageVersion>
<PackageVersion>1.3.8</PackageVersion>
<Version>$(PackageVersion)</Version>
<FileVersion>$(PackageVersion)</FileVersion>
</PropertyGroup>
Expand All @@ -25,7 +25,7 @@
<Copyright>MIT</Copyright>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>Roslyn,SourceGenerator,QuickApi</PackageTags>
<PackageReleaseNotes>add version gen</PackageReleaseNotes>
<PackageReleaseNotes>add assembly metadata gen</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/vipwan/Biwen.AutoClassGen</PackageProjectUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1573;1591;1712;SA1309;RS1035</NoWarn>
Expand Down
3 changes: 3 additions & 0 deletions Biwen.AutoClassGen.TestConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
Console.WriteLine(Biwen.AutoClassGen.TestConsole.Generated.Version.Current);
Console.WriteLine(Biwen.AutoClassGen.TestConsole.Generated.Version.AssemblyVersion);

// get assembly info
Console.WriteLine(Biwen.AutoClassGen.TestConsole.Generated.AssemblyMetadata.TargetFramework);

// Add services to the container.
builder.Services.AddLogging(config =>
{
Expand Down
1 change: 1 addition & 0 deletions Biwen.AutoClassGen.sln
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{02E9602B-E
Gen-AutoInject.md = Gen-AutoInject.md
Gen-Decor.md = Gen-Decor.md
Gen-Dto.md = Gen-Dto.md
Gen-Metadata.md = Gen-Metadata.md
Gen-request.md = Gen-request.md
Gen-Version.md = Gen-Version.md
LICENSE.txt = LICENSE.txt
Expand Down
7 changes: 7 additions & 0 deletions Gen-Metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## 自动创建程序集Metadata信息

#### 使用方式:
```csharp
Console.WriteLine({namespace}.Generated.AssemblyMetadata.TargetFramework);
//...
```
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dotnet add package Biwen.AutoClassGen
- [Gen Decoration Usage doc](https://github.com/vipwan/Biwen.AutoClassGen/blob/master/Gen-Decor.md)
- [Gen AutoInject Usage doc](https://github.com/vipwan/Biwen.AutoClassGen/blob/master/Gen-AutoInject.md)
- [Gen Version](https://github.com/vipwan/Biwen.AutoClassGen/blob/master/Gen-Version.md)
- [Gen Assembly Metadata](https://github.com/vipwan/Biwen.AutoClassGen/blob/master/Gen-Metadata.md)

### Used by
#### if you use this library, please tell me, I will add your project here.
Expand Down

0 comments on commit a77d17d

Please sign in to comment.