diff --git a/Source/MSBuild.Community.Tasks.Tests/AssemblyInfoTest.cs b/Source/MSBuild.Community.Tasks.Tests/AssemblyInfoTest.cs
index 0bc6ffaf..0fd8c1c3 100644
--- a/Source/MSBuild.Community.Tasks.Tests/AssemblyInfoTest.cs
+++ b/Source/MSBuild.Community.Tasks.Tests/AssemblyInfoTest.cs
@@ -184,6 +184,32 @@ public void IncludeAllowPartiallyTrustedCallers()
Assert.That(content.Contains("assembly: System.Security.AllowPartiallyTrustedCallers()"));
}
+ [Test(Description = "Create VersionInfo twice with OnlyIfChanged set and make sure it wasn't recreated the second time")]
+ public void AssemblyInfoNotRecreatedIfUnchanged()
+ {
+ AssemblyInfo task = new AssemblyInfo();
+ task.BuildEngine = new MockBuild();
+ task.CodeLanguage = "cs";
+ string outputFile = Path.Combine(testDirectory, "VersionInfoTwice.cs");
+ task.OutputFile = outputFile;
+ task.AssemblyVersion = "1.2.3.4";
+ task.AssemblyFileVersion = "1.2.3.4";
+ task.AssemblyInformationalVersion = "1.2.3.4";
+ task.GenerateClass = true;
+ task.OnlyIfChanged = true;
+
+ Assert.IsTrue(task.Execute(), "Execute Failed");
+ Assert.IsTrue(File.Exists(outputFile), "File missing: " + outputFile);
+
+ var time = File.GetLastWriteTime(outputFile);
+
+ // Create again, with OnlyIfChanged set it should not be recreated
+ Assert.IsTrue(task.Execute(), "Second execute failed");
+
+ var secondTime = File.GetLastWriteTime(outputFile);
+ Assert.AreEqual(time, secondTime, "File was recreated although it shouldn't be");
+ }
+
private AssemblyInfo CreateCSAssemblyInfo(string outputFile)
{
AssemblyInfo task = new AssemblyInfo();
diff --git a/Source/MSBuild.Community.Tasks/AssemblyInfo.cs b/Source/MSBuild.Community.Tasks/AssemblyInfo.cs
index 18731864..841fe07e 100644
--- a/Source/MSBuild.Community.Tasks/AssemblyInfo.cs
+++ b/Source/MSBuild.Community.Tasks/AssemblyInfo.cs
@@ -436,6 +436,11 @@ public bool UnmanagedCode
/// The ultimate resource fallback location.
public string UltimateResourceFallbackLocation { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the file should be generated only if different from any already existing file
+ ///
+ public bool OnlyIfChanged { get; set; }
+
///
/// Makes it possible to make certain assemblies able to use constructs marked as internal.
/// Example might be setting this value to "UnitTests" assembly. The typical use case might
@@ -491,12 +496,41 @@ public override bool Execute()
Encoding utf8WithSignature = new UTF8Encoding(true);
- using (StreamWriter writer = new StreamWriter(_outputFile, false, utf8WithSignature))
+ if (OnlyIfChanged && File.Exists(_outputFile))
{
- GenerateFile(writer);
- writer.Flush();
- writer.Close();
- Log.LogMessage("Created AssemblyInfo file \"{0}\".", _outputFile);
+ // The file already exists. If we generate an identical file, don't overwrite the existing one
+ using (var memoryStream = new MemoryStream())
+ {
+ using (StreamWriter writer = new StreamWriter(memoryStream, utf8WithSignature))
+ {
+ GenerateFile(writer);
+ writer.Flush();
+
+ using (var existingFile = File.OpenRead(_outputFile))
+ {
+ memoryStream.Seek(0, SeekOrigin.Begin);
+
+ if (StreamTools.StreamEquals(existingFile, memoryStream))
+ {
+ Log.LogMessage("Identical AssemblyInfo file \"{0}\" already exists.", _outputFile);
+ return true;
+ }
+ }
+
+ File.WriteAllBytes(_outputFile, memoryStream.ToArray());
+ Log.LogMessage("Created updated AssemblyInfo file \"{0}\".", _outputFile);
+ }
+ }
+ }
+ else
+ {
+ using (StreamWriter writer = new StreamWriter(_outputFile, false, utf8WithSignature))
+ {
+ GenerateFile(writer);
+ writer.Flush();
+ writer.Close();
+ Log.LogMessage("Created AssemblyInfo file \"{0}\".", _outputFile);
+ }
}
return true;
diff --git a/Source/MSBuild.Community.Tasks/MSBuild.Community.Tasks.csproj b/Source/MSBuild.Community.Tasks/MSBuild.Community.Tasks.csproj
index f4a16a13..1083567e 100644
--- a/Source/MSBuild.Community.Tasks/MSBuild.Community.Tasks.csproj
+++ b/Source/MSBuild.Community.Tasks/MSBuild.Community.Tasks.csproj
@@ -172,6 +172,7 @@
+
diff --git a/Source/MSBuild.Community.Tasks/StreamTools.cs b/Source/MSBuild.Community.Tasks/StreamTools.cs
new file mode 100644
index 00000000..47f8cf20
--- /dev/null
+++ b/Source/MSBuild.Community.Tasks/StreamTools.cs
@@ -0,0 +1,30 @@
+using System.IO;
+using System.Linq;
+
+namespace MSBuild.Community.Tasks
+{
+ internal static class StreamTools
+ {
+ public static bool StreamEquals(Stream stream1, Stream stream2)
+ {
+ const int bufferSize = 2048;
+ byte[] buffer1 = new byte[bufferSize]; //buffer size
+ byte[] buffer2 = new byte[bufferSize];
+ while (true)
+ {
+ int count1 = stream1.Read(buffer1, 0, bufferSize);
+ int count2 = stream2.Read(buffer2, 0, bufferSize);
+
+ if (count1 != count2)
+ return false;
+
+ if (count1 == 0)
+ return true;
+
+ // You might replace the following with an efficient "memcmp"
+ if (!buffer1.Take(count1).SequenceEqual(buffer2.Take(count2)))
+ return false;
+ }
+ }
+ }
+}