11namespace GitBuildInfo . SourceGenerator
22{
33 using System ;
4- using System . ComponentModel ;
5- using System . Diagnostics ;
6- using System . Globalization ;
74 using System . IO ;
85 using System . Linq ;
96 using System . Text ;
107 using System . Text . Json ;
118 using Microsoft . CodeAnalysis ;
129 using Microsoft . CodeAnalysis . CSharp ;
10+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
11+ using Microsoft . CodeAnalysis . Text ;
1312
1413 /// <summary>
1514 /// Source Generator for dumping git build information into a assembly level attribute on the compilation.
@@ -30,15 +29,28 @@ public void Execute(GeneratorExecutionContext context)
3029 return ;
3130 }
3231
32+ _ = context . AnalyzerConfigOptions . GlobalOptions . TryGetValue ( "build_property.projectdir" , out var projectdir ) ;
3333 var gitBuildInfoJsonFile = context . AdditionalFiles
3434 . FirstOrDefault ( af => string . Equals ( Path . GetFileName ( af . Path ) , "GitBuildInfo.json" , StringComparison . OrdinalIgnoreCase ) ) ;
35- if ( gitBuildInfoJsonFile is null )
35+ var gitInfoJsonFile = context . AdditionalFiles
36+ . FirstOrDefault ( af => string . Equals ( Path . GetFileName ( af . Path ) , "GitInfo.json" , StringComparison . OrdinalIgnoreCase ) ) ;
37+ if ( gitBuildInfoJsonFile is null || gitInfoJsonFile is null )
3638 {
3739 return ;
3840 }
39-
41+
42+ var jsonStr = gitBuildInfoJsonFile . GetText ( context . CancellationToken ) ! . ToString ( ) ;
4043 var options = JsonSerializer . Deserialize < GeneratorOptions > (
41- gitBuildInfoJsonFile . GetText ( context . CancellationToken ) ! . ToString ( ) ,
44+ jsonStr ,
45+ new JsonSerializerOptions
46+ {
47+ AllowTrailingCommas = true ,
48+ ReadCommentHandling = JsonCommentHandling . Skip ,
49+ PropertyNamingPolicy = JsonNamingPolicy . CamelCase ,
50+ } ) ;
51+ var jsonStr2 = gitInfoJsonFile . GetText ( context . CancellationToken ) ! . ToString ( ) ;
52+ var gitInfo = JsonSerializer . Deserialize < GitInfo > (
53+ jsonStr2 ,
4254 new JsonSerializerOptions
4355 {
4456 AllowTrailingCommas = true ,
@@ -51,6 +63,7 @@ public void Execute(GeneratorExecutionContext context)
5163 }
5264
5365 var splitted = options ! . AssemblyType ! . Contains ( "." ) ? options ! . AssemblyType . Split ( '.' ) : new string [ ] { } ;
66+ var splitted2 = new Span < string > ( splitted , 0 , splitted . Length - 1 ) ;
5467 var splittedLen = splitted . Length ;
5568 var usingStr = new StringBuilder ( ) ;
5669 var gitinformationNamespace = "Elskom.Generic.Libs" ;
@@ -59,50 +72,114 @@ public void Execute(GeneratorExecutionContext context)
5972 // skip the last value.
6073 if ( value != splitted [ splittedLen - 1 ] )
6174 {
62- _ = usingStr . Append ( value != splitted [ 0 ] ? " ." : value ) ;
75+ _ = usingStr . Append ( value != splitted [ splittedLen - 2 ] ? $ " { value } ." : value ) ;
6376 }
6477 }
6578
66- context . AddSource ( "GitAssemblyInfo.g.cs" ,
67- string . Format (
68- CultureInfo . InvariantCulture ,
69- $ "// <autogenerated/>{ 0 } { 1 } { 0 } { 0 } [assembly: GitInformationAttribute(\" { 2 } \" , \" { 3 } \" , \" { 4 } \" , typeof({ 5 } { 6 } ))]{ 0 } ",
70- Environment . NewLine ,
71- splittedLen > 0 && ! string . Equals (
72- gitinformationNamespace ,
73- usingStr . ToString ( ) ,
74- StringComparison . Ordinal ) ? $ "using { usingStr } ;{ Environment . NewLine } using { gitinformationNamespace } ;" : $ "using { gitinformationNamespace } ;",
75- this . RunGit ( "describe --all --always --dirty" , Directory . GetParent ( gitBuildInfoJsonFile . Path ) . FullName ) ,
76- this . RunGit ( "rev-parse --short HEAD" , Directory . GetParent ( gitBuildInfoJsonFile . Path ) . FullName ) ,
77- this . RunGit ( "name-rev --name-only HEAD" , Directory . GetParent ( gitBuildInfoJsonFile . Path ) . FullName ) ,
78- splittedLen > 0 ? splitted [ splittedLen - 1 ] : options ! . AssemblyType ,
79- options ! . IsGeneric ? "<>" : string . Empty ) ) ;
79+ var generated = GenerateCode (
80+ options ,
81+ splitted2 . ToArray ( ) ,
82+ gitinformationNamespace ,
83+ gitInfo ! . GitHead ! ,
84+ gitInfo . CommitHash ! ,
85+ gitInfo . GitBranch ! ,
86+ splittedLen > 0 ? splitted [ splittedLen - 1 ] : options ! . AssemblyType ) ;
87+ context . AddSource ( "GitAssemblyInfo.g.cs" , SourceText . From ( generated . ToFullString ( ) , Encoding . UTF8 ) ) ;
8088 }
8189
82- private string RunGit ( string arguments , string workingDirectory )
90+ private static CompilationUnitSyntax GenerateCode ( GeneratorOptions options , string [ ] usings , string originalnamespace , string arg1 , string arg2 , string arg3 , string typeName )
91+ => SyntaxFactory . CompilationUnit ( ) . WithUsings (
92+ SyntaxFactory . List (
93+ string . Equals ( string . Join ( "." , usings ) , originalnamespace , StringComparison . Ordinal )
94+ ? new UsingDirectiveSyntax [ ] {
95+ AddUsing ( new string [ ] { "Elskom" , "Generic" , "Libs" } , true )
96+ }
97+ : new UsingDirectiveSyntax [ ] {
98+ AddUsing ( new string [ ] { "Elskom" , "Generic" , "Libs" } , true ) ,
99+ AddUsing ( usings , false )
100+ } ) )
101+ . WithAttributeLists (
102+ SyntaxFactory . SingletonList (
103+ SyntaxFactory . AttributeList (
104+ SyntaxFactory . SingletonSeparatedList (
105+ SyntaxFactory . Attribute ( SyntaxFactory . IdentifierName ( "GitInformationAttribute" ) )
106+ . WithArgumentList (
107+ SyntaxFactory . AttributeArgumentList (
108+ SyntaxFactory . SeparatedList < AttributeArgumentSyntax > (
109+ MakeAttributeArgumentList ( options , new string [ ] { arg1 , arg2 , arg3 } , typeName ) ) ) ) ) )
110+ . WithOpenBracketToken (
111+ SyntaxFactory . Token (
112+ SyntaxFactory . TriviaList ( SyntaxFactory . LineFeed ) ,
113+ SyntaxKind . OpenBracketToken ,
114+ SyntaxFactory . TriviaList ( ) ) )
115+ . WithTarget (
116+ SyntaxFactory . AttributeTargetSpecifier ( SyntaxFactory . Token ( SyntaxKind . AssemblyKeyword ) )
117+ . WithColonToken (
118+ SyntaxFactory . Token (
119+ SyntaxFactory . TriviaList ( ) ,
120+ SyntaxKind . ColonToken ,
121+ SyntaxFactory . TriviaList ( SyntaxFactory . Space ) ) ) )
122+ . WithCloseBracketToken (
123+ SyntaxFactory . Token (
124+ SyntaxFactory . TriviaList ( ) ,
125+ SyntaxKind . CloseBracketToken ,
126+ SyntaxFactory . TriviaList ( SyntaxFactory . LineFeed ) ) ) ) ) ;
127+
128+ private static UsingDirectiveSyntax AddUsing ( string [ ] strings , bool autogeneratedheader )
83129 {
84- using var pro1 = new Process ( ) ;
85- pro1 . StartInfo . FileName = "git" ;
86- pro1 . StartInfo . Arguments = arguments ;
87- pro1 . StartInfo . RedirectStandardOutput = true ;
88- pro1 . StartInfo . UseShellExecute = false ;
89- pro1 . StartInfo . CreateNoWindow = true ;
90- pro1 . StartInfo . WorkingDirectory = workingDirectory ;
91- try
130+ NameSyntax ? qualifiedName = null ;
131+ for ( var index = 0 ; index < strings . Length ; index ++ )
92132 {
93- _ = pro1 . Start ( ) ;
94- var git_out = pro1 . StandardOutput . ReadToEnd ( ) ;
95- pro1 . WaitForExit ( ) ;
96-
97- // handle all cases of possible endlines.
98- git_out = git_out . Replace ( "\r \n " , string . Empty ) ;
99- git_out = git_out . Replace ( "\n " , string . Empty ) ;
100- return git_out . Replace ( "\r " , string . Empty ) ;
133+ if ( index == 0 && strings . Length > 1 )
134+ {
135+ qualifiedName = SyntaxFactory . QualifiedName (
136+ SyntaxFactory . IdentifierName ( strings [ index ] ) ,
137+ SyntaxFactory . IdentifierName ( strings [ index + 1 ] ) ) ;
138+ index ++ ;
139+ }
140+ else
141+ {
142+ qualifiedName = strings . Length == 1
143+ ? SyntaxFactory . IdentifierName ( strings [ index ] )
144+ : SyntaxFactory . QualifiedName ( qualifiedName ! , SyntaxFactory . IdentifierName ( strings [ index ] ) ) ;
145+ }
101146 }
102- catch ( Win32Exception )
147+
148+ return SyntaxFactory . UsingDirective ( qualifiedName ! )
149+ . WithUsingKeyword ( SyntaxFactory . Token (
150+ SyntaxFactory . TriviaList ( autogeneratedheader ? new [ ] { SyntaxFactory . Comment ( "// <autogenerated/>" ) , SyntaxFactory . LineFeed } : Array . Empty < SyntaxTrivia > ( ) ) ,
151+ SyntaxKind . UsingKeyword ,
152+ SyntaxFactory . TriviaList ( SyntaxFactory . Space ) ) )
153+ . WithSemicolonToken ( SyntaxFactory . Token (
154+ SyntaxFactory . TriviaList ( ) ,
155+ SyntaxKind . SemicolonToken ,
156+ SyntaxFactory . TriviaList ( SyntaxFactory . LineFeed ) ) ) ;
157+ }
158+
159+ private static SyntaxNodeOrToken [ ] MakeAttributeArgumentList ( GeneratorOptions options , string [ ] args , string typeName )
160+ {
161+ var lst = new SyntaxNodeOrToken [ 7 ] ;
162+ var lstIndex = 0 ;
163+ foreach ( var arg in args )
103164 {
104- return "Not a git clone or git is not in Path." ;
165+ lst [ lstIndex ] = SyntaxFactory . AttributeArgument (
166+ SyntaxFactory . LiteralExpression (
167+ SyntaxKind . StringLiteralExpression ,
168+ SyntaxFactory . Literal ( arg ) ) ) ;
169+ lstIndex ++ ;
170+ lst [ lstIndex ] = SyntaxFactory . Token (
171+ SyntaxFactory . TriviaList ( ) ,
172+ SyntaxKind . CommaToken ,
173+ SyntaxFactory . TriviaList ( SyntaxFactory . Space ) ) ;
174+ lstIndex ++ ;
105175 }
176+
177+ lst [ lstIndex ] = SyntaxFactory . AttributeArgument (
178+ SyntaxFactory . TypeOfExpression (
179+ options . IsGeneric
180+ ? SyntaxFactory . GenericName ( typeName )
181+ : SyntaxFactory . IdentifierName ( typeName ) ) ) ;
182+ return lst ;
106183 }
107184 }
108185}
0 commit comments