Trigger rebuild when the CLI changed

- Stamp each project with the CLI version it was last compiled with
- Rebuild those projects with a local version file that does not match the one of the current CLI that is building it
This commit is contained in:
Mihai Codoban 2016-03-03 22:57:43 -08:00
parent 7a82a98e4c
commit f14b4cbd3d
6 changed files with 142 additions and 23 deletions

View file

@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Reflection;
namespace Microsoft.DotNet.Cli.Utils
{
public static class DotnetFiles
{
/// <summary>
/// The CLI ships with a .version file that stores the commit information and CLI version
/// </summary>
public static string VersionFile => Path.GetFullPath(Path.Combine(typeof(DotnetFiles).GetTypeInfo().Assembly.Location, "..", ".version"));
}
}

View file

@ -31,6 +31,11 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
return baseOption;
}
public static string GetSDKVersionFile(this ProjectContext context, string configuration, string buildBasePath, string outputPath)
{
var intermediatePath = context.GetOutputPaths(configuration, buildBasePath, outputPath).IntermediateOutputDirectoryPath;
return Path.Combine(intermediatePath, ".SDKVersion");
}
// used in incremental compilation for the key file
public static CommonCompilerOptions ResolveCompilationOptions(this ProjectContext context, string configuration)

View file

@ -159,8 +159,7 @@ namespace Microsoft.DotNet.Cli
private static string GetCommitSha()
{
// The CLI ships with a .version file that stores the commit information
var versionFile = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, ".version"));
var versionFile = DotnetFiles.VersionFile;
if (File.Exists(versionFile))
{

View file

@ -53,17 +53,23 @@ namespace Microsoft.DotNet.Tools.Build
private bool CompileRootProject(bool incremental)
{
if (incremental && !NeedsRebuilding(_rootProject, _rootProjectDependencies))
try
{
// todo: what if the previous build had errors / warnings and nothing changed? Need to propagate them in case of incremental
return true;
if (incremental && !NeedsRebuilding(_rootProject, _rootProjectDependencies))
{
return true;
}
var success = InvokeCompileOnRootProject();
PrintSummary(success);
return success;
}
finally
{
StampProjectWithSDKVersion(_rootProject);
}
var success = InvokeCompileOnRootProject();
PrintSummary(success);
return success;
}
private bool CompileDependencies(bool incremental)
@ -75,28 +81,37 @@ namespace Microsoft.DotNet.Tools.Build
foreach (var dependency in Sort(_rootProjectDependencies.ProjectDependenciesWithSources))
{
if (incremental && !DependencyNeedsRebuilding(dependency))
{
continue;
}
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework, new[] { _rootProject.RuntimeIdentifier });
if (!InvokeCompileOnDependency(dependency))
try
{
return false;
if (incremental && !NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue)))
{
continue;
}
if (!InvokeCompileOnDependency(dependency))
{
return false;
}
}
finally
{
StampProjectWithSDKVersion(dependencyProjectContext);
}
}
return true;
}
private bool DependencyNeedsRebuilding(ProjectDescription dependency)
{
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework, new[] { _rootProject.RuntimeIdentifier });
return NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue));
}
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies)
{
if (CLIChangedSinceLastCompilation(project))
{
Reporter.Output.WriteLine($"Project {project.GetDisplayName()} will be compiled because the CLI changed");
return true;
}
var compilerIO = GetCompileIO(project, dependencies);
// rebuild if empty inputs / outputs
@ -174,6 +189,48 @@ namespace Microsoft.DotNet.Tools.Build
return true;
}
private bool CLIChangedSinceLastCompilation(ProjectContext project)
{
var currentVersionFile = DotnetFiles.VersionFile;
var versionFileFromLastCompile = project.GetSDKVersionFile(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
if (!File.Exists(currentVersionFile))
{
// this CLI does not have a version file; cannot tell if CLI changed
return false;
}
if (!File.Exists(versionFileFromLastCompile))
{
// this is the first compilation; cannot tell if CLI changed
return false;
}
var versionsAreEqual = string.Equals(File.ReadAllText(currentVersionFile), File.ReadAllText(versionFileFromLastCompile), StringComparison.OrdinalIgnoreCase);
return !versionsAreEqual;
}
private void StampProjectWithSDKVersion(ProjectContext project)
{
if (File.Exists(DotnetFiles.VersionFile))
{
var projectVersionFile = project.GetSDKVersionFile(_args.ConfigValue, _args.BuildBasePathValue,_args.OutputValue);
var parentDirectory = Path.GetDirectoryName(projectVersionFile);
if (!Directory.Exists(parentDirectory))
{
Directory.CreateDirectory(parentDirectory);
}
File.Copy(DotnetFiles.VersionFile, projectVersionFile, true);
}
else
{
Reporter.Verbose.WriteLine($"Project {project.GetDisplayName()} was not stamped with a CLI version because the version file does not exist: {DotnetFiles.VersionFile}");
}
}
private void PrintSummary(bool success)
{

View file

@ -124,5 +124,12 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
return executablePath;
}
protected string GetIntermediaryOutputPath()
{
var executablePath = Path.Combine(TestProjectRoot, "obj", "Debug", "netstandardapp1.5");
return executablePath;
}
}
}

View file

@ -4,6 +4,7 @@
using System;
using System.IO;
using System.Linq;
using FluentAssertions;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
@ -79,6 +80,40 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
Assert.Contains("does not have a lock file", buildResult.StdErr);
}
[Fact]
public void TestModifiedVersionFile()
{
CreateTestInstance();
BuildProject().Should().HaveCompiledProject(MainProject);
//change version file
var versionFile = Path.Combine(GetIntermediaryOutputPath(), ".SDKVersion");
File.Exists(versionFile).Should().BeTrue();
File.AppendAllText(versionFile, "text");
//assert rebuilt
BuildProject().Should().HaveCompiledProject(MainProject);
}
[Fact]
public void TestNoVersionFile()
{
CreateTestInstance();
BuildProject().Should().HaveCompiledProject(MainProject);
//delete version file
var versionFile = Path.Combine(GetIntermediaryOutputPath(), ".SDKVersion");
File.Exists(versionFile).Should().BeTrue();
File.Delete(versionFile);
File.Exists(versionFile).Should().BeFalse();
//assert build skipped due to no version file
BuildProject().Should().HaveSkippedProjectCompilation(MainProject);
//the version file should have been regenerated during the build, even if compilation got skipped
File.Exists(versionFile).Should().BeTrue();
}
[Fact]
public void TestRebuildChangedLockFile()
{