Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for issue #149 - Adding F# support for AssemblyInfo generation #255

Merged
merged 5 commits into from
Nov 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nerdbank.GitVersioning.Tasks;
using Xunit;

namespace NerdBank.GitVersioning.Tests
{
public class AssemblyInfoTest
{
[Fact]
public void FSharpGenerator()
{
var info = new AssemblyVersionInfo();
info.AssemblyCompany = "company";
info.AssemblyFileVersion = "1.3.1.0";
info.AssemblyVersion = "1.3.0.0";
info.CodeLanguage = "f#";

var built = info.BuildCode();

var expected = @"//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace AssemblyInfo
[<assembly: System.Reflection.AssemblyVersionAttribute(""1.3.0.0"")>]
[<assembly: System.Reflection.AssemblyFileVersionAttribute(""1.3.1.0"")>]
[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("""")>]
do()
type internal ThisAssembly() =
static member internal AssemblyVersion = ""1.3.0.0""
static member internal AssemblyFileVersion = ""1.3.1.0""
static member internal AssemblyCompany = ""company""
static member internal RootNamespace = """"
do()
";
Assert.Equal(expected, built);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<EmbeddedResource Include="repos\submodules.7z" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MSBuildExtensionTask\MSBuildExtensionTask.csproj" />
<ProjectReference Include="..\Nerdbank.GitVersioning.Tasks\Nerdbank.GitVersioning.Tasks.csproj" />
<ProjectReference Include="..\NerdBank.GitVersioning\NerdBank.GitVersioning.csproj" />
</ItemGroup>
Expand Down
91 changes: 75 additions & 16 deletions src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
Expand All @@ -22,7 +21,7 @@ public class AssemblyVersionInfo : Task
};

private CodeCompileUnit generatedFile;
#else
#endif
private const string FileHeaderComment = @"------------------------------------------------------------------------------
<auto-generated>
This code was generated by a tool.
Expand All @@ -36,8 +35,6 @@ the code is regenerated.

private CodeGenerator generator;

#endif

[Required]
public string CodeLanguage { get; set; }

Expand Down Expand Up @@ -101,7 +98,17 @@ public override bool Execute()
}
else
{
this.Log.LogError("CodeDomProvider not available for language: {0}. No version info will be embedded into assembly.", this.CodeLanguage);
// attempt to use local codegen
string fileContent = this.BuildCode();
if (fileContent != null)
{
Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile));
Utilities.FileOperationWithRetry(() => File.WriteAllText(this.OutputFile, fileContent));
}
else
{
this.Log.LogError("CodeDomProvider not available for language: {0}. No version info will be embedded into assembly.", this.CodeLanguage);
}
}

return !this.Log.HasLoggedErrors;
Expand Down Expand Up @@ -205,24 +212,36 @@ private static CodeAttributeDeclaration DeclareAttribute(Type attributeType, par
#else

public override bool Execute()
{
string fileContent = this.BuildCode();
if (fileContent != null)
{
Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile));
Utilities.FileOperationWithRetry(() => File.WriteAllText(this.OutputFile, fileContent));
}

return !this.Log.HasLoggedErrors;
}

#endif

public string BuildCode()
{
this.generator = this.CreateGenerator();
if (this.generator != null)
{
this.generator.AddComment(FileHeaderComment);
this.generator.AddBlankLine();
this.CreateAssemblyAttributes();
this.CreateThisAssemblyClass();

Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile));
string fileContent = this.generator.GetCode();
Utilities.FileOperationWithRetry(() => File.WriteAllText(this.OutputFile, fileContent));
this.generator.EmitNamespaceIfRequired(this.RootNamespace ?? "AssemblyInfo");
this.GenerateAssemblyAttributes();
this.GenerateThisAssemblyClass();
return this.generator.GetCode();
}

return !this.Log.HasLoggedErrors;
return null;
}

private void CreateAssemblyAttributes()
private void GenerateAssemblyAttributes()
{
this.generator.DeclareAttribute(typeof(AssemblyVersionAttribute), this.AssemblyVersion);
this.generator.DeclareAttribute(typeof(AssemblyFileVersionAttribute), this.AssemblyFileVersion);
Expand All @@ -240,7 +259,7 @@ private void CreateAssemblyAttributes()
}
}

private void CreateThisAssemblyClass()
private void GenerateThisAssemblyClass()
{
this.generator.StartThisAssemblyClass();

Expand Down Expand Up @@ -280,6 +299,7 @@ private void CreateThisAssemblyClass()

this.generator.EndThisAssemblyClass();
}

private CodeGenerator CreateGenerator()
{
switch (this.CodeLanguage.ToLowerInvariant())
Expand All @@ -290,8 +310,9 @@ private CodeGenerator CreateGenerator()
case "visualbasic":
case "vb":
return new VisualBasicCodeGenerator();
case "f#":
return new FSharpCodeGenerator();
default:
this.Log.LogError("Code provider not available for language: {0}. No version info will be embedded into assembly.", this.CodeLanguage);
return null;
}
}
Expand All @@ -315,6 +336,12 @@ internal CodeGenerator()

internal abstract void EndThisAssemblyClass();

/// <summary>
/// Gives languages that *require* a namespace a chance to emit such.
/// </summary>
/// <param name="ns">The RootNamespace of the project.</param>
internal virtual void EmitNamespaceIfRequired(string ns) { }

internal string GetCode() => this.codeBuilder.ToString();

internal void AddBlankLine()
Expand All @@ -334,6 +361,39 @@ protected void AddCodeComment(string comment, string token)
}
}

private class FSharpCodeGenerator : CodeGenerator
{
internal override void AddComment(string comment)
{
this.AddCodeComment(comment, "//");
}

internal override void AddThisAssemblyMember(string name, string value)
{
this.codeBuilder.AppendLine($" static member internal {name} = \"{value}\"");
}

internal override void EmitNamespaceIfRequired(string ns)
{
this.codeBuilder.AppendLine($"namespace {ns}");
}

internal override void DeclareAttribute(Type type, string arg)
{
this.codeBuilder.AppendLine($"[<assembly: {type.FullName}(\"{arg}\")>]");
}

internal override void EndThisAssemblyClass()
{
this.codeBuilder.AppendLine("do()");
}

internal override void StartThisAssemblyClass()
{
this.codeBuilder.AppendLine("do()\r\ntype internal ThisAssembly() =");
}
}

private class CSharpCodeGenerator : CodeGenerator
{
internal override void AddComment(string comment)
Expand Down Expand Up @@ -389,7 +449,6 @@ internal override void EndThisAssemblyClass()
this.codeBuilder.AppendLine("End Class");
}
}
#endif

private static string ToHex(byte[] data)
{
Expand Down