Skip to content
This repository was archived by the owner on Dec 2, 2021. It is now read-only.

Commit e4b38cb

Browse files
asherber304NotModified
authored andcommitted
cleanup
nameof Record innerexception backwards comp Added Support for UseFileVersion and OverwriteFileVersion
1 parent 222e95c commit e4b38cb

File tree

10 files changed

+172
-58
lines changed

10 files changed

+172
-58
lines changed

AssemblyToProcess/AssemblyInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
[assembly: AssemblyTitle("AssemblyToProcess")]
44
[assembly: AssemblyProduct("AssemblyToProcess")]
55
[assembly: AssemblyVersion("1.0.0.0")]
6+
[assembly: AssemblyFileVersion("4.5.6.7")]
67
//[assembly: AssemblyInformationalVersionAttribute("1.0.0.0/aString")]

AssemblyToProcessExistingAttribute/AssemblyInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
[assembly: AssemblyTitle("AssemblyToProcessExistingAttribute")]
44
[assembly: AssemblyProduct("AssemblyToProcessExistingAttribute")]
55
[assembly: AssemblyVersion("1.0.0")]
6+
[assembly: AssemblyFileVersion("4.5.6.7")]
67
[assembly: AssemblyInformationalVersionAttribute("%version3%+%branch%.%githash% %haschanges% %utcnow% %now:yyMMdd%")]

Fody/Configuration.cs

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
public class Configuration
55
{
6-
public bool UseProject;
7-
public string ChangeString = "HasChanges";
6+
public bool UseProject { get; set; }
7+
public bool UseFileVersion { get; set; }
8+
public bool OverwriteFileVersion { get; set; } = true;
9+
10+
public string ChangeString { get; set; } = "HasChanges";
811

912
public Configuration(XElement config)
1013
{
@@ -14,22 +17,50 @@ public Configuration(XElement config)
1417
}
1518

1619
var attr = config.Attribute("UseProjectGit");
17-
if (attr != null)
20+
if (HasValue(attr))
1821
{
19-
try
20-
{
21-
UseProject = Convert.ToBoolean(attr.Value);
22-
}
23-
catch (Exception)
24-
{
25-
throw new WeavingException($"Unable to parse '{attr.Value}' as a boolean, please use true or false.");
26-
}
22+
UseProject = ConvertAndThrowIfNotBoolean(attr.Value);
23+
}
24+
25+
attr = config.Attribute("UseFileVersion");
26+
if (HasValue(attr))
27+
{
28+
UseFileVersion = ConvertAndThrowIfNotBoolean(attr.Value);
2729
}
2830

2931
attr = config.Attribute("ChangeString");
30-
if (!string.IsNullOrWhiteSpace(attr?.Value))
32+
if (HasValue(attr))
3133
{
3234
ChangeString = attr.Value;
3335
}
36+
37+
if (UseFileVersion)
38+
OverwriteFileVersion = false;
39+
else
40+
{
41+
attr = config.Attribute("OverwriteFileVersion");
42+
if (HasValue(attr))
43+
{
44+
OverwriteFileVersion = ConvertAndThrowIfNotBoolean(attr.Value);
45+
}
46+
}
47+
}
48+
49+
private static bool HasValue(XAttribute attr)
50+
{
51+
return !string.IsNullOrWhiteSpace(attr?.Value);
52+
}
53+
54+
private static bool ConvertAndThrowIfNotBoolean(string value)
55+
{
56+
try
57+
{
58+
var result = Convert.ToBoolean(value);
59+
return result;
60+
}
61+
catch
62+
{
63+
throw new WeavingException($"Unable to parse '{value}' as a boolean; please use 'true' or 'false'.");
64+
}
3465
}
3566
}

Fody/Internal/FormatStringTokenResolver.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using System;
22
using System.Text.RegularExpressions;
33
using LibGit2Sharp;
4-
using Mono.Cecil;
54

65
namespace Stamp.Fody.Internal
76
{
8-
internal class FormatStringTokenResolver
7+
using Version = System.Version;
8+
9+
internal static class FormatStringTokenResolver
910
{
1011
private static Regex reEnvironmentToken = new Regex(@"%env\[([^\]]+)]%");
1112
private static Regex reNow = new Regex(@"%now:([^%]+)%");
@@ -14,16 +15,15 @@ internal class FormatStringTokenResolver
1415
private static DateTime now = DateTime.Now;
1516
private static DateTime utcNow = DateTime.UtcNow;
1617

17-
public string ReplaceTokens(string template, ModuleDefinition moduleDefinition, Repository repo, string changestring)
18+
public static string ReplaceTokens(string template, Version version, Repository repo, string changestring)
1819
{
19-
var assemblyVersion = moduleDefinition.Assembly.Name.Version;
2020
var branch = repo.Head;
2121

22-
template = template.Replace("%version%", assemblyVersion.ToString());
23-
template = template.Replace("%version1%", assemblyVersion.ToString(1));
24-
template = template.Replace("%version2%", assemblyVersion.ToString(2));
25-
template = template.Replace("%version3%", assemblyVersion.ToString(3));
26-
template = template.Replace("%version4%", assemblyVersion.ToString(4));
22+
template = template.Replace("%version%", version.ToString());
23+
template = template.Replace("%version1%", version.ToString(1));
24+
template = template.Replace("%version2%", version.ToString(2));
25+
template = template.Replace("%version3%", version.ToString(3));
26+
template = template.Replace("%version4%", version.ToString(4));
2727

2828
template = template.Replace("%now%", now.ToShortDateString());
2929
template = template.Replace("%utcnow%", utcNow.ToShortDateString());

Fody/ModuleWeaver.cs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
34
using System.IO;
45
using System.Linq;
56

@@ -15,16 +16,18 @@
1516
public class ModuleWeaver : BaseModuleWeaver
1617
{
1718
private static bool isPathSet;
18-
private readonly FormatStringTokenResolver formatStringTokenResolver;
1919
private string assemblyInfoVersion;
20-
private Version assemblyVersion;
20+
private Version versionToUse;
2121
private bool dotGitDirExists;
2222

23+
24+
private const string InfoAttributeName = nameof(System.Reflection.AssemblyInformationalVersionAttribute);
25+
private const string FileAttributeName = nameof(System.Reflection.AssemblyFileVersionAttribute);
26+
2327
public ModuleWeaver()
2428
{
2529
LogInfo = s => { };
2630
LogWarning = s => { };
27-
formatStringTokenResolver = new FormatStringTokenResolver();
2831
}
2932

3033
public override void Execute()
@@ -57,13 +60,16 @@ public override void Execute()
5760
return;
5861
}
5962

60-
assemblyVersion = ModuleDefinition.Assembly.Name.Version;
63+
if (!config.UseFileVersion)
64+
versionToUse = ModuleDefinition.Assembly.Name.Version;
65+
else
66+
versionToUse = GetAssemblyFileVersion(customAttributes);
6167

62-
var customAttribute = customAttributes.FirstOrDefault(x => x.AttributeType.Name == "AssemblyInformationalVersionAttribute");
68+
var customAttribute = GetCustomAttribute(customAttributes, InfoAttributeName);
6369
if (customAttribute != null)
6470
{
6571
assemblyInfoVersion = (string)customAttribute.ConstructorArguments[0].Value;
66-
assemblyInfoVersion = formatStringTokenResolver.ReplaceTokens(assemblyInfoVersion, ModuleDefinition, repo, config.ChangeString);
72+
assemblyInfoVersion = FormatStringTokenResolver.ReplaceTokens(assemblyInfoVersion, versionToUse, repo, config.ChangeString);
6773
VerifyStartsWithVersion(assemblyInfoVersion);
6874
customAttribute.ConstructorArguments[0] = new CustomAttributeArgument(ModuleDefinition.TypeSystem.String, assemblyInfoVersion);
6975
}
@@ -73,14 +79,32 @@ public override void Execute()
7379
var constructor = ModuleDefinition.ImportReference(versionAttribute.Methods.First(x => x.IsConstructor));
7480
customAttribute = new CustomAttribute(constructor);
7581

76-
assemblyInfoVersion = $"{assemblyVersion} Head:'{repo.Head.FriendlyName}' Sha:{branch.Tip.Sha}{(repo.IsClean() ? "" : " " + config.ChangeString)}";
82+
assemblyInfoVersion = $"{versionToUse} Head:'{repo.Head.FriendlyName}' Sha:{branch.Tip.Sha}{(repo.IsClean() ? "" : " " + config.ChangeString)}";
7783

7884
customAttribute.ConstructorArguments.Add(new CustomAttributeArgument(ModuleDefinition.TypeSystem.String, assemblyInfoVersion));
7985
customAttributes.Add(customAttribute);
8086
}
8187
}
8288
}
8389

90+
private static CustomAttribute GetCustomAttribute(ICollection<CustomAttribute> attributes, string attributeName)
91+
{
92+
return attributes.FirstOrDefault(x => x.AttributeType.Name == attributeName);
93+
}
94+
95+
private Version GetAssemblyFileVersion(ICollection<CustomAttribute> customAttributes)
96+
{
97+
var afvAttribute = GetCustomAttribute(customAttributes, FileAttributeName);
98+
if (afvAttribute == null)
99+
{
100+
throw new WeavingException("AssemblyFileVersion attribute could not be found.");
101+
}
102+
103+
var assemblyFileVersionString = (string) afvAttribute.ConstructorArguments[0].Value;
104+
VerifyStartsWithVersion(assemblyFileVersionString);
105+
return Version.Parse(assemblyFileVersionString);
106+
}
107+
84108
private void VerifyStartsWithVersion(string versionString)
85109
{
86110
var prefix = new string(versionString.TakeWhile(x => char.IsDigit(x) || x == '.').ToArray());
@@ -166,15 +190,15 @@ public override void AfterWeaving()
166190
var versions = reader.Read();
167191

168192
var fixedFileInfo = versions.FixedFileInfo.Value;
169-
fixedFileInfo.FileVersion = assemblyVersion;
170-
fixedFileInfo.ProductVersion = assemblyVersion;
193+
fixedFileInfo.FileVersion = versionToUse;
194+
fixedFileInfo.ProductVersion = versionToUse;
171195
versions.FixedFileInfo = fixedFileInfo;
172196

173197
foreach (var stringTable in versions.StringFileInfo)
174198
{
175199
if (stringTable.Values.ContainsKey("FileVersion"))
176200
{
177-
stringTable.Values["FileVersion"] = assemblyVersion.ToString();
201+
stringTable.Values["FileVersion"] = versionToUse.ToString();
178202
}
179203

180204
if (stringTable.Values.ContainsKey("ProductVersion"))

Fody/WeavingException.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ public WeavingException(string message)
77
{
88

99
}
10+
11+
/// <inheritdoc />
12+
public WeavingException(string message, Exception innerException) : base(message, innerException)
13+
{
14+
}
1015
}

README.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Extracts the git information from disk, combines it with the assembly version, a
3434
So if your assembly version is `1.0.0.0`, the working branch is `master` and the last commit is `759e9ddb53271dfa9335a3b27e452749a9b22280` then the following attribute will be added to the assembly.
3535

3636
```c#
37-
[assembly: AssemblyInformationalVersion("1.0.0.0 Head:'master' Sha:759e9ddb53271dfa9335a3b27e452749a9b22280")]
37+
[assembly: AssemblyInformationalVersion("1.0.0.0 Head:'master' Sha:759e9ddb53271dfa9335a3b27e452749a9b22280")]
3838
```
3939

4040

@@ -52,6 +52,8 @@ The tokens are:
5252
- `%version4%` is replaced with the major, minor, revision, and build version (`1.0.0.0`)
5353
- `%now%` is replaced with the current short date
5454
- `%utcnow%` is replaced with the current utc short date
55+
- `%now%` is replaced with the current short date
56+
- `%utcnow%` is replaced with the current utc short date
5557
- `%githash%` is replaced with the SHA1 hash of the branch tip of the repository
5658
- `%shorthash%` is replaced with the first eight characters of `%githash%`
5759
- `%branch%` is replaced with the branch name of the repository
@@ -78,7 +80,6 @@ Define the string used to indicate that the code was built from a non clean repo
7880
<Stamp ChangeString="New text" />
7981
```
8082

81-
8283
### UseProjectGit
8384

8485
Define if you want to start Stamp to start searching for the Git repository in the ProjectDir (`true`) or the SolutionDir (`false`).
@@ -89,6 +90,28 @@ Define if you want to start Stamp to start searching for the Git repository in t
8990
<Stamp UseProjectGit='true' />
9091
```
9192

93+
### OverwriteFileVersion
94+
95+
(new in 2.0)
96+
97+
By default, Stamp will overwrite the `AssemblyFileVersion` with the `AssemblyVersion`. Setting this to `false` will preserve the existing `AssemblyFileVersion`.
98+
99+
*Default is `true`*
100+
101+
```xml
102+
<Stamp OverwriteFileVersion='false' />
103+
```
104+
105+
### UseFileVersion
106+
107+
(new in 2.0)
108+
109+
By default, Stamp uses the value from `AssemblyVersion` to construct the `AssemblyInformationalVersion`. Set this to `true` to use the `AssemblyFileVersion` instead. **Note:** If this is set to `true`, `OverwriteFileVersion` will be `false` and will ignore any value explicitly set.
110+
111+
*Default is `false`*
112+
```xml
113+
<Stamp UseFileVersion='true' />
114+
```
92115

93116
## Icon
94117

Tests/TaskTests.cs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.Reflection;
55
using Mono.Cecil;
66
using NUnit.Framework;
7+
using System.Xml.Linq;
8+
using System;
79

810
[TestFixture]
911
public class TaskTests
@@ -12,19 +14,25 @@ public class TaskTests
1214
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
1315
private string beforeAssemblyPath;
1416
private string afterAssemblyPath;
17+
protected XElement config;
1518

16-
public TaskTests()
19+
[OneTimeSetUp]
20+
public void Setup()
1721
{
1822
beforeAssemblyPath = Path.GetFullPath(Path.Combine(TestContext.CurrentContext.TestDirectory, @"..\..\..\AssemblyToProcess\bin\Debug\AssemblyToProcess.dll"));
1923
#if (!DEBUG)
2024
beforeAssemblyPath = beforeAssemblyPath.Replace("Debug", "Release");
2125
#endif
2226

23-
afterAssemblyPath = beforeAssemblyPath.Replace(".dll", "2.dll");
27+
afterAssemblyPath = beforeAssemblyPath.Replace(".dll", $"{Guid.NewGuid().ToString()}.dll");
2428
File.Copy(beforeAssemblyPath, afterAssemblyPath, true);
2529

2630
using (var moduleDefinition = ModuleDefinition.ReadModule(beforeAssemblyPath))
2731
{
32+
33+
var versionInfo = FileVersionInfo.GetVersionInfo(afterAssemblyPath);
34+
Trace.WriteLine($"Before: AssemblyVersion={moduleDefinition.Assembly.Name.Version}, FileVersion={versionInfo.FileVersion}, Config={config}");
35+
2836
var currentDirectory = AssemblyLocation.CurrentDirectory();
2937

3038
var weavingTask = new ModuleWeaver
@@ -33,6 +41,7 @@ public TaskTests()
3341
AddinDirectoryPath = currentDirectory,
3442
SolutionDirectoryPath = currentDirectory,
3543
AssemblyFilePath = afterAssemblyPath,
44+
Config = config
3645
};
3746

3847
weavingTask.Execute();
@@ -44,16 +53,15 @@ public TaskTests()
4453
assembly = Assembly.LoadFile(afterAssemblyPath);
4554
}
4655

47-
4856
[Test]
4957
public void EnsureAttributeExists()
5058
{
5159
var customAttributes = (AssemblyInformationalVersionAttribute)assembly
52-
.GetCustomAttributes(typeof (AssemblyInformationalVersionAttribute), false)
60+
.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)
5361
.First();
5462
Assert.IsNotNull(customAttributes.InformationalVersion);
5563
Assert.IsNotEmpty(customAttributes.InformationalVersion);
56-
Trace.WriteLine(customAttributes.InformationalVersion);
64+
Trace.WriteLine($"InfoVersion: {customAttributes.InformationalVersion}");
5765
}
5866

5967
[Test]
@@ -64,8 +72,8 @@ public void Win32Resource()
6472
Assert.IsNotEmpty(versionInfo.ProductVersion);
6573
Assert.IsNotNull(versionInfo.FileVersion);
6674
Assert.IsNotEmpty(versionInfo.FileVersion);
67-
Trace.WriteLine(versionInfo.ProductVersion);
68-
Trace.WriteLine(versionInfo.FileVersion);
75+
Trace.WriteLine($"ProductVersion: {versionInfo.ProductVersion}");
76+
Trace.WriteLine($"FileVersion: {versionInfo.FileVersion}");
6977
}
7078

7179

@@ -77,4 +85,22 @@ public void PeVerify()
7785
}
7886
#endif
7987

88+
}
89+
90+
[TestFixture]
91+
class UseFileVersionTests : TaskTests
92+
{
93+
public UseFileVersionTests()
94+
{
95+
config = XElement.Parse("<Stamp UseFileVersion=\"true\" />");
96+
}
97+
}
98+
99+
[TestFixture]
100+
class OverwriteFileVersionTests : TaskTests
101+
{
102+
public OverwriteFileVersionTests()
103+
{
104+
config = XElement.Parse("<Stamp OverwriteFileVersion=\"false\" />");
105+
}
80106
}

0 commit comments

Comments
 (0)