Add version suffix to build cache to ensure incremental builds are reset when it changes (#3246)
* add test for #2687 * fix #2687 by writing version suffix to build cache
This commit is contained in:
parent
e9d3a0903d
commit
d5b1ee138f
5 changed files with 86 additions and 10 deletions
|
@ -11,7 +11,7 @@ namespace Microsoft.DotNet.TestFramework
|
|||
{
|
||||
public class TestInstance: TestDirectory
|
||||
{
|
||||
// made tolower because the rest of the class works with normalized tolower strings
|
||||
// made tolower because the rest of the class works with normalized tolower strings
|
||||
private static readonly IEnumerable<string> BuildArtifactBlackList = new List<string>() {".IncrementalCache", ".SDKVersion"}.Select(s => s.ToLower()).ToArray();
|
||||
|
||||
private string _testAssetRoot;
|
||||
|
@ -78,9 +78,9 @@ namespace Microsoft.DotNet.TestFramework
|
|||
.Where(dir =>
|
||||
{
|
||||
dir = dir.ToLower();
|
||||
return dir.EndsWith($"{System.IO.Path.DirectorySeparatorChar}bin")
|
||||
return dir.EndsWith($"{System.IO.Path.DirectorySeparatorChar}bin")
|
||||
|| dir.Contains($"{System.IO.Path.DirectorySeparatorChar}bin{System.IO.Path.DirectorySeparatorChar}")
|
||||
|| dir.EndsWith($"{System.IO.Path.DirectorySeparatorChar}obj")
|
||||
|| dir.EndsWith($"{System.IO.Path.DirectorySeparatorChar}obj")
|
||||
|| dir.Contains($"{System.IO.Path.DirectorySeparatorChar}obj{System.IO.Path.DirectorySeparatorChar}");
|
||||
});
|
||||
|
||||
|
@ -94,10 +94,10 @@ namespace Microsoft.DotNet.TestFramework
|
|||
{
|
||||
file = file.ToLower();
|
||||
|
||||
var isArtifact = file.Contains($"{System.IO.Path.DirectorySeparatorChar}bin{System.IO.Path.DirectorySeparatorChar}")
|
||||
var isArtifact = file.Contains($"{System.IO.Path.DirectorySeparatorChar}bin{System.IO.Path.DirectorySeparatorChar}")
|
||||
|| file.Contains($"{System.IO.Path.DirectorySeparatorChar}obj{System.IO.Path.DirectorySeparatorChar}");
|
||||
|
||||
var isBlackListed = BuildArtifactBlackList.Any(b => file.Contains(b));
|
||||
var isBlackListed = BuildArtifactBlackList.Any(b => file.Contains(b));
|
||||
|
||||
return isArtifact && !isBlackListed;
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
|
@ -44,7 +45,8 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
_args.ShouldSkipDependencies,
|
||||
_args.ConfigValue,
|
||||
_args.BuildBasePathValue,
|
||||
_args.OutputValue
|
||||
_args.OutputValue,
|
||||
BuildIncrementalArgumentList(_args)
|
||||
);
|
||||
|
||||
_scriptRunner = new ScriptRunner();
|
||||
|
@ -52,6 +54,11 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
_commandFactory = new DotNetCommandFactory();
|
||||
}
|
||||
|
||||
private static IDictionary<string, string> BuildIncrementalArgumentList(BuildCommandApp args) => new Dictionary<string, string>()
|
||||
{
|
||||
["version-suffix"] = args.VersionSuffixValue
|
||||
};
|
||||
|
||||
private void StampProjectWithSDKVersion(ProjectContext project)
|
||||
{
|
||||
if (File.Exists(DotnetFiles.VersionFile))
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
@ -11,14 +12,21 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
{
|
||||
internal class IncrementalCache
|
||||
{
|
||||
private const string BuildArgumentsKeyName = "buildArguments";
|
||||
private const string InputsKeyName = "inputs";
|
||||
private const string OutputsKeyNane = "outputs";
|
||||
|
||||
public CompilerIO CompilerIO { get; }
|
||||
|
||||
public IncrementalCache(CompilerIO compilerIO)
|
||||
/// <summary>
|
||||
/// Captures parameters that affect compilation outputs.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> BuildArguments { get; }
|
||||
|
||||
public IncrementalCache(CompilerIO compilerIO, IEnumerable<KeyValuePair<string, string>> parameters)
|
||||
{
|
||||
CompilerIO = compilerIO;
|
||||
BuildArguments = parameters.ToDictionary(p => p.Key, p => p.Value);
|
||||
}
|
||||
|
||||
public void WriteToFile(string cacheFile)
|
||||
|
@ -32,6 +40,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
var rootObject = new JObject();
|
||||
rootObject[InputsKeyName] = new JArray(CompilerIO.Inputs);
|
||||
rootObject[OutputsKeyNane] = new JArray(CompilerIO.Outputs);
|
||||
rootObject[BuildArgumentsKeyName] = JObject.FromObject(BuildArguments);
|
||||
|
||||
JsonSerializer.Create().Serialize(streamWriter, rootObject);
|
||||
}
|
||||
|
@ -67,8 +76,9 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
|
||||
var inputs = ReadArray<string>(jObject, InputsKeyName);
|
||||
var outputs = ReadArray<string>(jObject, OutputsKeyNane);
|
||||
var parameters = ReadDictionary(jObject, BuildArgumentsKeyName);
|
||||
|
||||
return new IncrementalCache(new CompilerIO(inputs, outputs));
|
||||
return new IncrementalCache(new CompilerIO(inputs, outputs), parameters);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -77,6 +87,18 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<KeyValuePair<string, string>> ReadDictionary(JObject jObject, string keyName)
|
||||
{
|
||||
var obj = jObject[keyName] as JObject;
|
||||
|
||||
if(obj == null)
|
||||
{
|
||||
return Enumerable.Empty<KeyValuePair<string, string>>();
|
||||
}
|
||||
|
||||
return obj.Properties().ToDictionary(p => p.Name, p => p.Value.ToString());
|
||||
}
|
||||
|
||||
private static IEnumerable<T> ReadArray<T>(JObject jObject, string keyName)
|
||||
{
|
||||
var array = jObject.Value<JToken>(keyName)?.Values<T>();
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
private readonly string _configuration;
|
||||
private readonly string _buildBasePath;
|
||||
private readonly string _outputPath;
|
||||
private readonly IDictionary<string, string> _incrementalAffectingArguments;
|
||||
|
||||
public IncrementalManager(
|
||||
ProjectBuilder projectBuilder,
|
||||
|
@ -28,7 +29,8 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
bool shouldSkipDependencies,
|
||||
string configuration,
|
||||
string buildBasePath,
|
||||
string outputPath)
|
||||
string outputPath,
|
||||
IDictionary<string, string> incrementalAffectingArguments)
|
||||
{
|
||||
_projectBuilder = projectBuilder;
|
||||
_compilerIoManager = compilerIOManager;
|
||||
|
@ -37,6 +39,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
_configuration = configuration;
|
||||
_buildBasePath = buildBasePath;
|
||||
_outputPath = outputPath;
|
||||
_incrementalAffectingArguments = incrementalAffectingArguments;
|
||||
}
|
||||
|
||||
public IncrementalResult NeedsRebuilding(ProjectGraphNode graphNode)
|
||||
|
@ -156,6 +159,21 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
return new IncrementalResult("Input items added from last build", diffResult.Additions);
|
||||
}
|
||||
|
||||
var keys = incrementalCache.BuildArguments.Keys.Union(_incrementalAffectingArguments.Keys);
|
||||
var mismatchedKeys = keys.Where(k =>
|
||||
{
|
||||
string cachedVal;
|
||||
string currentVal;
|
||||
|
||||
return !incrementalCache.BuildArguments.TryGetValue(k, out cachedVal) ||
|
||||
!_incrementalAffectingArguments.TryGetValue(k, out currentVal) ||
|
||||
!string.Equals(cachedVal ?? string.Empty, currentVal ?? string.Empty, StringComparison.Ordinal);
|
||||
});
|
||||
if (mismatchedKeys.Any())
|
||||
{
|
||||
return new IncrementalResult("Build arguments changed since last build", mismatchedKeys);
|
||||
}
|
||||
|
||||
return IncrementalResult.DoesNotNeedRebuild;
|
||||
}
|
||||
|
||||
|
@ -195,7 +213,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
{
|
||||
var incrementalCacheFile = graphNode.ProjectContext.IncrementalCacheFile(_configuration, _buildBasePath, _outputPath);
|
||||
|
||||
var incrementalCache = new IncrementalCache(_compilerIoManager.GetCompileIO(graphNode));
|
||||
var incrementalCache = new IncrementalCache(_compilerIoManager.GetCompileIO(graphNode), _incrementalAffectingArguments);
|
||||
incrementalCache.WriteToFile(incrementalCacheFile);
|
||||
}
|
||||
}
|
||||
|
|
29
test/dotnet-build.Tests/IncrementalTestsVersionSuffix.cs
Normal file
29
test/dotnet-build.Tests/IncrementalTestsVersionSuffix.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Builder.Tests
|
||||
{
|
||||
public class IncrementalTestsVersionSuffix : IncrementalTestBase
|
||||
{
|
||||
[Fact]
|
||||
public void TestRebuildWhenVersionSuffixChanged()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("TestSimpleIncrementalApp")
|
||||
.WithLockFiles();
|
||||
|
||||
// Build with Version Suffix 1
|
||||
var command = new BuildCommand(testInstance.TestRoot, versionSuffix: "1");
|
||||
var result = command.ExecuteWithCapturedOutput();
|
||||
|
||||
// Verify the result
|
||||
result.Should().HaveCompiledProject("TestSimpleIncrementalApp", ".NETCoreApp,Version=v1.0");
|
||||
|
||||
// Build with Version Suffix 2
|
||||
command = new BuildCommand(testInstance.TestRoot, versionSuffix: "2");
|
||||
result = command.ExecuteWithCapturedOutput();
|
||||
|
||||
// Verify the result
|
||||
result.Should().HaveCompiledProject("TestSimpleIncrementalApp", ".NETCoreApp,Version=v1.0");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue