diff --git a/GenerationFailedException.cs b/GenerationFailedException.cs
index 4bbda78..cfd6579 100644
--- a/GenerationFailedException.cs
+++ b/GenerationFailedException.cs
@@ -25,4 +25,4 @@ protected GenerationFailedException(SerializationInfo info, StreamingContext con
{
}
}
-}
\ No newline at end of file
+}
diff --git a/GeneratorOptions.cs b/GeneratorOptions.cs
index 40ac406..53bfb9f 100644
--- a/GeneratorOptions.cs
+++ b/GeneratorOptions.cs
@@ -1,20 +1,13 @@
namespace GitBuildInfo.SourceGenerator
{
- ///
- /// Describes the options that feed into code generation.
- ///
+ using System.Text.Json.Serialization;
+
public record GeneratorOptions
{
- ///
- /// Gets the type to use to apply the attribute to embed the git information in that is within the assembly it is being applied to.
- ///
- /// The type to use to apply the attribute to embed the git information in that is within the assembly it is being applied to.
+ [JsonPropertyName("AssemblyType")]
public string? AssemblyType { get; set; }
- ///
- /// Gets if the type specified in AssemblyType is a generic type, by default this is set to false to indicate that the type is not a generic type.
- ///
- /// If the type specified in AssemblyType is a generic type, by default this is set to false to indicate that the type is not a generic type.
+ [JsonPropertyName("IsGeneric")]
public bool IsGeneric { get; set; }
}
}
diff --git a/GitBuildInfo.SourceGenerator.csproj b/GitBuildInfo.SourceGenerator.csproj
index 33613b0..78beb65 100644
--- a/GitBuildInfo.SourceGenerator.csproj
+++ b/GitBuildInfo.SourceGenerator.csproj
@@ -5,8 +5,8 @@
netstandard2.0
latest
enable
- 1.0.3
- Replaced property inits with setters on GeneratorOptions.
+ 1.0.4
+ Fixed generating sources.
Els_kom org.
Els_kom org.
Copyright (c) 2021
@@ -39,9 +39,7 @@
-
-
diff --git a/GitBuildInfo.SourceGenerator.nuspec b/GitBuildInfo.SourceGenerator.nuspec
index bec20e8..da037af 100644
--- a/GitBuildInfo.SourceGenerator.nuspec
+++ b/GitBuildInfo.SourceGenerator.nuspec
@@ -14,9 +14,7 @@
Copyright (c) 2021
-
-
-
+
diff --git a/GitInfo.cs b/GitInfo.cs
new file mode 100644
index 0000000..e1decad
--- /dev/null
+++ b/GitInfo.cs
@@ -0,0 +1,16 @@
+namespace GitBuildInfo.SourceGenerator
+{
+ using System.Text.Json.Serialization;
+
+ public record GitInfo
+ {
+ [JsonPropertyName("GitHead")]
+ public string? GitHead { get; set; }
+
+ [JsonPropertyName("CommitHash")]
+ public string? CommitHash { get; set; }
+
+ [JsonPropertyName("GitBranch")]
+ public string? GitBranch { get; set; }
+ }
+}
diff --git a/SourceGenerator.cs b/SourceGenerator.cs
index e8d3468..ba8de23 100644
--- a/SourceGenerator.cs
+++ b/SourceGenerator.cs
@@ -1,15 +1,14 @@
namespace GitBuildInfo.SourceGenerator
{
using System;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
+ using Microsoft.CodeAnalysis.CSharp.Syntax;
+ using Microsoft.CodeAnalysis.Text;
///
/// Source Generator for dumping git build information into a assembly level attribute on the compilation.
@@ -30,15 +29,28 @@ public void Execute(GeneratorExecutionContext context)
return;
}
+ _ = context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.projectdir", out var projectdir);
var gitBuildInfoJsonFile = context.AdditionalFiles
.FirstOrDefault(af => string.Equals(Path.GetFileName(af.Path), "GitBuildInfo.json", StringComparison.OrdinalIgnoreCase));
- if (gitBuildInfoJsonFile is null)
+ var gitInfoJsonFile = context.AdditionalFiles
+ .FirstOrDefault(af => string.Equals(Path.GetFileName(af.Path), "GitInfo.json", StringComparison.OrdinalIgnoreCase));
+ if (gitBuildInfoJsonFile is null || gitInfoJsonFile is null)
{
return;
}
-
+
+ var jsonStr = gitBuildInfoJsonFile.GetText(context.CancellationToken)!.ToString();
var options = JsonSerializer.Deserialize(
- gitBuildInfoJsonFile.GetText(context.CancellationToken)!.ToString(),
+ jsonStr,
+ new JsonSerializerOptions
+ {
+ AllowTrailingCommas = true,
+ ReadCommentHandling = JsonCommentHandling.Skip,
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ });
+ var jsonStr2 = gitInfoJsonFile.GetText(context.CancellationToken)!.ToString();
+ var gitInfo = JsonSerializer.Deserialize(
+ jsonStr2,
new JsonSerializerOptions
{
AllowTrailingCommas = true,
@@ -51,6 +63,7 @@ public void Execute(GeneratorExecutionContext context)
}
var splitted = options!.AssemblyType!.Contains(".") ? options!.AssemblyType.Split('.') : new string[] { };
+ var splitted2 = new Span(splitted, 0, splitted.Length - 1);
var splittedLen = splitted.Length;
var usingStr = new StringBuilder();
var gitinformationNamespace = "Elskom.Generic.Libs";
@@ -59,50 +72,114 @@ public void Execute(GeneratorExecutionContext context)
// skip the last value.
if (value != splitted[splittedLen - 1])
{
- _ = usingStr.Append(value != splitted[0] ? "." : value);
+ _ = usingStr.Append(value != splitted[splittedLen - 2] ? $"{value}." : value);
}
}
- context.AddSource("GitAssemblyInfo.g.cs",
- string.Format(
- CultureInfo.InvariantCulture,
- $"// {0}{1}{0}{0}[assembly: GitInformationAttribute(\"{2}\", \"{3}\", \"{4}\", typeof({5}{6}))]{0}",
- Environment.NewLine,
- splittedLen > 0 && !string.Equals(
- gitinformationNamespace,
- usingStr.ToString(),
- StringComparison.Ordinal) ? $"using {usingStr};{Environment.NewLine}using {gitinformationNamespace};" : $"using {gitinformationNamespace};",
- this.RunGit("describe --all --always --dirty", Directory.GetParent(gitBuildInfoJsonFile.Path).FullName),
- this.RunGit("rev-parse --short HEAD", Directory.GetParent(gitBuildInfoJsonFile.Path).FullName),
- this.RunGit("name-rev --name-only HEAD", Directory.GetParent(gitBuildInfoJsonFile.Path).FullName),
- splittedLen > 0 ? splitted[splittedLen - 1] : options!.AssemblyType,
- options!.IsGeneric ? "<>" : string.Empty));
+ var generated = GenerateCode(
+ options,
+ splitted2.ToArray(),
+ gitinformationNamespace,
+ gitInfo!.GitHead!,
+ gitInfo.CommitHash!,
+ gitInfo.GitBranch!,
+ splittedLen > 0 ? splitted[splittedLen - 1] : options!.AssemblyType);
+ context.AddSource("GitAssemblyInfo.g.cs", SourceText.From(generated.ToFullString(), Encoding.UTF8));
}
- private string RunGit(string arguments, string workingDirectory)
+ private static CompilationUnitSyntax GenerateCode(GeneratorOptions options, string[] usings, string originalnamespace, string arg1, string arg2, string arg3, string typeName)
+ => SyntaxFactory.CompilationUnit().WithUsings(
+ SyntaxFactory.List(
+ string.Equals(string.Join(".", usings), originalnamespace, StringComparison.Ordinal)
+ ? new UsingDirectiveSyntax[] {
+ AddUsing(new string[] { "Elskom", "Generic", "Libs" }, true)
+ }
+ : new UsingDirectiveSyntax[] {
+ AddUsing(new string[] { "Elskom", "Generic", "Libs" }, true),
+ AddUsing(usings, false)
+ }))
+ .WithAttributeLists(
+ SyntaxFactory.SingletonList(
+ SyntaxFactory.AttributeList(
+ SyntaxFactory.SingletonSeparatedList(
+ SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("GitInformationAttribute"))
+ .WithArgumentList(
+ SyntaxFactory.AttributeArgumentList(
+ SyntaxFactory.SeparatedList(
+ MakeAttributeArgumentList(options, new string[] { arg1, arg2, arg3 }, typeName))))))
+ .WithOpenBracketToken(
+ SyntaxFactory.Token(
+ SyntaxFactory.TriviaList(SyntaxFactory.LineFeed),
+ SyntaxKind.OpenBracketToken,
+ SyntaxFactory.TriviaList()))
+ .WithTarget(
+ SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword))
+ .WithColonToken(
+ SyntaxFactory.Token(
+ SyntaxFactory.TriviaList(),
+ SyntaxKind.ColonToken,
+ SyntaxFactory.TriviaList(SyntaxFactory.Space))))
+ .WithCloseBracketToken(
+ SyntaxFactory.Token(
+ SyntaxFactory.TriviaList(),
+ SyntaxKind.CloseBracketToken,
+ SyntaxFactory.TriviaList(SyntaxFactory.LineFeed)))));
+
+ private static UsingDirectiveSyntax AddUsing(string[] strings, bool autogeneratedheader)
{
- using var pro1 = new Process();
- pro1.StartInfo.FileName = "git";
- pro1.StartInfo.Arguments = arguments;
- pro1.StartInfo.RedirectStandardOutput = true;
- pro1.StartInfo.UseShellExecute = false;
- pro1.StartInfo.CreateNoWindow = true;
- pro1.StartInfo.WorkingDirectory = workingDirectory;
- try
+ NameSyntax? qualifiedName = null;
+ for (var index = 0; index < strings.Length; index++)
{
- _ = pro1.Start();
- var git_out = pro1.StandardOutput.ReadToEnd();
- pro1.WaitForExit();
-
- // handle all cases of possible endlines.
- git_out = git_out.Replace("\r\n", string.Empty);
- git_out = git_out.Replace("\n", string.Empty);
- return git_out.Replace("\r", string.Empty);
+ if (index == 0 && strings.Length > 1)
+ {
+ qualifiedName = SyntaxFactory.QualifiedName(
+ SyntaxFactory.IdentifierName(strings[index]),
+ SyntaxFactory.IdentifierName(strings[index + 1]));
+ index++;
+ }
+ else
+ {
+ qualifiedName = strings.Length == 1
+ ? SyntaxFactory.IdentifierName(strings[index])
+ : SyntaxFactory.QualifiedName(qualifiedName!, SyntaxFactory.IdentifierName(strings[index]));
+ }
}
- catch (Win32Exception)
+
+ return SyntaxFactory.UsingDirective(qualifiedName!)
+ .WithUsingKeyword(SyntaxFactory.Token(
+ SyntaxFactory.TriviaList(autogeneratedheader ? new[] { SyntaxFactory.Comment("// "), SyntaxFactory.LineFeed } : Array.Empty()),
+ SyntaxKind.UsingKeyword,
+ SyntaxFactory.TriviaList(SyntaxFactory.Space)))
+ .WithSemicolonToken(SyntaxFactory.Token(
+ SyntaxFactory.TriviaList(),
+ SyntaxKind.SemicolonToken,
+ SyntaxFactory.TriviaList(SyntaxFactory.LineFeed)));
+ }
+
+ private static SyntaxNodeOrToken[] MakeAttributeArgumentList(GeneratorOptions options, string[] args, string typeName)
+ {
+ var lst = new SyntaxNodeOrToken[7];
+ var lstIndex = 0;
+ foreach (var arg in args)
{
- return "Not a git clone or git is not in Path.";
+ lst[lstIndex] = SyntaxFactory.AttributeArgument(
+ SyntaxFactory.LiteralExpression(
+ SyntaxKind.StringLiteralExpression,
+ SyntaxFactory.Literal(arg)));
+ lstIndex++;
+ lst[lstIndex] = SyntaxFactory.Token(
+ SyntaxFactory.TriviaList(),
+ SyntaxKind.CommaToken,
+ SyntaxFactory.TriviaList(SyntaxFactory.Space));
+ lstIndex++;
}
+
+ lst[lstIndex] = SyntaxFactory.AttributeArgument(
+ SyntaxFactory.TypeOfExpression(
+ options.IsGeneric
+ ? SyntaxFactory.GenericName(typeName)
+ : SyntaxFactory.IdentifierName(typeName)));
+ return lst;
}
}
}
diff --git a/build/GitBuildInfo.SourceGenerator.props b/build/GitBuildInfo.SourceGenerator.props
index 4c560c0..e46acb9 100644
--- a/build/GitBuildInfo.SourceGenerator.props
+++ b/build/GitBuildInfo.SourceGenerator.props
@@ -2,5 +2,6 @@
+
diff --git a/build/GitBuildInfo.SourceGenerator.targets b/build/GitBuildInfo.SourceGenerator.targets
new file mode 100644
index 0000000..b729887
--- /dev/null
+++ b/build/GitBuildInfo.SourceGenerator.targets
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /// A MSBuild task that generates the msbuild information for an assembly.
+ ///
+ /// Note: use in the BeforeBuild target.
+ ///
+ public class GitInfoTask : Task
+ {
+ ///
+ /// Gets or sets the generated output file path.
+ ///
+ [Required]
+ public string OutputPath { get; set; }
+
+ ///
+ public override bool Execute()
+ {
+ this.RunGit("describe --all --always --dirty", out var git_out1);
+ this.RunGit("rev-parse --short HEAD", out var git_out2);
+ this.RunGit("name-rev --name-only HEAD", out var git_out3);
+ var outputData = $"{{{Environment.NewLine} \"GitHead\": \"{git_out1}\",{Environment.NewLine} \"CommitHash\": \"{git_out2}\",{Environment.NewLine} \"GitBranch\": \"{git_out3}\"{Environment.NewLine}}}";
+ // patch 112019: only print the getting build info from git message from the initial call to this task.
+ // all other calls will not print anything to avoid spamming up the build output.
+ try
+ {
+ if (!File.Exists(this.OutputPath) || (File.Exists(this.OutputPath) && !string.Equals(outputData, File.ReadAllText(this.OutputPath), StringComparison.Ordinal)))
+ {
+ this.Log.LogMessage(MessageImportance.High, "Getting build info from git");
+ File.WriteAllText(this.OutputPath, outputData);
+ }
+ }
+ catch (IOException)
+ {
+ // catch I/O error from being unable to open the file for checking it's contents.
+ }
+ return true;
+ }
+
+ private void RunGit(string arguments, out string git_out)
+ {
+ using var pro1 = new Process();
+ pro1.StartInfo.FileName = "git";
+ pro1.StartInfo.Arguments = arguments;
+ pro1.StartInfo.RedirectStandardOutput = true;
+ pro1.StartInfo.UseShellExecute = false;
+ pro1.StartInfo.CreateNoWindow = true;
+ pro1.StartInfo.WorkingDirectory = Path.GetFullPath(this.OutputPath).Replace(Path.GetFileName(this.OutputPath), string.Empty);
+ try
+ {
+ _ = pro1.Start();
+ git_out = pro1.StandardOutput.ReadToEnd();
+ pro1.WaitForExit();
+ // handle all cases of possible endlines.
+ git_out = git_out.Replace("\r\n", string.Empty);
+ git_out = git_out.Replace("\n", string.Empty);
+ git_out = git_out.Replace("\r", string.Empty);
+ }
+ catch (Win32Exception)
+ {
+ git_out = "Not a git clone or git is not in Path.";
+ }
+ }
+ }
+}]]>
+
+
+
+
+
+
+
+