Merge pull request #930 from cdmihai/cdmihai/buildCommandTestingReleasePR

Release PR: Incremental build tests and improvements
This commit is contained in:
Piotr Puszkiewicz 2016-01-21 12:31:25 -08:00
commit 14f665eb30
39 changed files with 782 additions and 113 deletions

View file

@ -87,6 +87,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.Publ
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestLibrary", "test\TestProjects\TestLibrary\TestLibrary.xproj", "{947DD232-8D9B-4B78-9C6A-94F807D2DD58}" Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestLibrary", "test\TestProjects\TestLibrary\TestLibrary.xproj", "{947DD232-8D9B-4B78-9C6A-94F807D2DD58}"
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.Builder.Tests", "test\Microsoft.DotNet.Tools.Builder.Tests\Microsoft.DotNet.Tools.Builder.Tests.xproj", "{833FFEE1-7EED-4F51-8DFD-946D48833333}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestProjectToProjectDependencies", "test\TestProjects\TestProjectToProjectDependencies\TestProjectToProjectDependencies.xproj", "{947DD232-8D9B-4B78-9C6A-94F807D22222}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -659,6 +663,38 @@ Global
{947DD232-8D9B-4B78-9C6A-94F807D2DD58}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {947DD232-8D9B-4B78-9C6A-94F807D2DD58}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D2DD58}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {947DD232-8D9B-4B78-9C6A-94F807D2DD58}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D2DD58}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {947DD232-8D9B-4B78-9C6A-94F807D2DD58}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Debug|Any CPU.Build.0 = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Debug|x64.ActiveCfg = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Debug|x64.Build.0 = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Release|Any CPU.ActiveCfg = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Release|Any CPU.Build.0 = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Release|x64.ActiveCfg = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.Release|x64.Build.0 = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{833FFEE1-7EED-4F51-8DFD-946D48833333}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Debug|Any CPU.Build.0 = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Debug|x64.ActiveCfg = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Debug|x64.Build.0 = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Release|Any CPU.ActiveCfg = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Release|Any CPU.Build.0 = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Release|x64.ActiveCfg = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.Release|x64.Build.0 = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{947DD232-8D9B-4B78-9C6A-94F807D22222}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -700,5 +736,7 @@ Global
{833FFEE1-7EED-4F51-8DFD-946D48893D6E} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {833FFEE1-7EED-4F51-8DFD-946D48893D6E} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{386D412C-003C-47B1-8258-0E35865CB7C4} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {386D412C-003C-47B1-8258-0E35865CB7C4} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{947DD232-8D9B-4B78-9C6A-94F807D2DD58} = {713CBFBB-5392-438D-B766-A9A585EF1BB8} {947DD232-8D9B-4B78-9C6A-94F807D2DD58} = {713CBFBB-5392-438D-B766-A9A585EF1BB8}
{833FFEE1-7EED-4F51-8DFD-946D48833333} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{947DD232-8D9B-4B78-9C6A-94F807D22222} = {713CBFBB-5392-438D-B766-A9A585EF1BB8}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -11,9 +11,10 @@ $TestBinRoot = "$RepoRoot\artifacts\tests"
$TestProjects = @( $TestProjects = @(
"E2E", "E2E",
"StreamForwarderTests" "StreamForwarderTests",
"Microsoft.DotNet.Tools.Publish.Tests" "Microsoft.DotNet.Tools.Publish.Tests",
"Microsoft.DotNet.Tools.Compiler.Tests" "Microsoft.DotNet.Tools.Compiler.Tests",
"Microsoft.DotNet.Tools.Builder.Tests"
) )
# Publish each test project # Publish each test project

View file

@ -24,6 +24,7 @@ TestProjects=( \
StreamForwarderTests \ StreamForwarderTests \
Microsoft.DotNet.Tools.Publish.Tests \ Microsoft.DotNet.Tools.Publish.Tests \
Microsoft.DotNet.Tools.Compiler.Tests \ Microsoft.DotNet.Tools.Compiler.Tests \
Microsoft.DotNet.Tools.Builder.Tests \
) )
for project in ${TestProjects[@]} for project in ${TestProjects[@]}

View file

@ -15,12 +15,19 @@ namespace Microsoft.DotNet.ProjectModel.Graph
public static readonly int CurrentVersion = 2; public static readonly int CurrentVersion = 2;
public static readonly string FileName = "project.lock.json"; public static readonly string FileName = "project.lock.json";
public string LockFilePath { get; }
public int Version { get; set; } public int Version { get; set; }
public IList<ProjectFileDependencyGroup> ProjectFileDependencyGroups { get; set; } = new List<ProjectFileDependencyGroup>(); public IList<ProjectFileDependencyGroup> ProjectFileDependencyGroups { get; set; } = new List<ProjectFileDependencyGroup>();
public IList<LockFilePackageLibrary> PackageLibraries { get; set; } = new List<LockFilePackageLibrary>(); public IList<LockFilePackageLibrary> PackageLibraries { get; set; } = new List<LockFilePackageLibrary>();
public IList<LockFileProjectLibrary> ProjectLibraries { get; set; } = new List<LockFileProjectLibrary>(); public IList<LockFileProjectLibrary> ProjectLibraries { get; set; } = new List<LockFileProjectLibrary>();
public IList<LockFileTarget> Targets { get; set; } = new List<LockFileTarget>(); public IList<LockFileTarget> Targets { get; set; } = new List<LockFileTarget>();
public LockFile(string lockFilePath)
{
LockFilePath = lockFilePath;
}
public bool IsValidForProject(Project project) public bool IsValidForProject(Project project)
{ {
string message; string message;

View file

@ -15,26 +15,26 @@ namespace Microsoft.DotNet.ProjectModel.Graph
{ {
public static class LockFileReader public static class LockFileReader
{ {
public static LockFile Read(string filePath) public static LockFile Read(string lockFilePath)
{ {
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var stream = new FileStream(lockFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{ {
try try
{ {
return Read(stream); return Read(lockFilePath, stream);
} }
catch (FileFormatException ex) catch (FileFormatException ex)
{ {
throw ex.WithFilePath(filePath); throw ex.WithFilePath(lockFilePath);
} }
catch (Exception ex) catch (Exception ex)
{ {
throw FileFormatException.Create(ex, filePath); throw FileFormatException.Create(ex, lockFilePath);
} }
} }
} }
internal static LockFile Read(Stream stream) internal static LockFile Read(string lockFilePath, Stream stream)
{ {
try try
{ {
@ -43,7 +43,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
if (jobject != null) if (jobject != null)
{ {
return ReadLockFile(jobject); return ReadLockFile(lockFilePath, jobject);
} }
else else
{ {
@ -53,16 +53,16 @@ namespace Microsoft.DotNet.ProjectModel.Graph
catch catch
{ {
// Ran into parsing errors, mark it as unlocked and out-of-date // Ran into parsing errors, mark it as unlocked and out-of-date
return new LockFile return new LockFile(lockFilePath)
{ {
Version = int.MinValue Version = int.MinValue
}; };
} }
} }
private static LockFile ReadLockFile(JsonObject cursor) private static LockFile ReadLockFile(string lockFilePath, JsonObject cursor)
{ {
var lockFile = new LockFile(); var lockFile = new LockFile(lockFilePath);
lockFile.Version = ReadInt(cursor, "version", defaultValue: int.MinValue); lockFile.Version = ReadInt(cursor, "version", defaultValue: int.MinValue);
lockFile.Targets = ReadObject(cursor.ValueAsJsonObject("targets"), ReadTarget); lockFile.Targets = ReadObject(cursor.ValueAsJsonObject("targets"), ReadTarget);
lockFile.ProjectFileDependencyGroups = ReadObject(cursor.ValueAsJsonObject("projectFileDependencyGroups"), ReadProjectFileDependencyGroup); lockFile.ProjectFileDependencyGroups = ReadObject(cursor.ValueAsJsonObject("projectFileDependencyGroups"), ReadProjectFileDependencyGroup);

View file

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Resolution; using Microsoft.DotNet.ProjectModel.Resolution;
using NuGet.Frameworks; using NuGet.Frameworks;
@ -22,6 +23,8 @@ namespace Microsoft.DotNet.ProjectModel
public Project ProjectFile => RootProject.Project; public Project ProjectFile => RootProject.Project;
public LockFile LockFile { get; }
public string RootDirectory => GlobalSettings.DirectoryPath; public string RootDirectory => GlobalSettings.DirectoryPath;
public string ProjectDirectory => ProjectFile.ProjectDirectory; public string ProjectDirectory => ProjectFile.ProjectDirectory;
@ -36,7 +39,8 @@ namespace Microsoft.DotNet.ProjectModel
NuGetFramework targetFramework, NuGetFramework targetFramework,
string runtimeIdentifier, string runtimeIdentifier,
string packagesDirectory, string packagesDirectory,
LibraryManager libraryManager) LibraryManager libraryManager,
LockFile lockfile)
{ {
GlobalSettings = globalSettings; GlobalSettings = globalSettings;
RootProject = rootProject; RootProject = rootProject;
@ -44,6 +48,7 @@ namespace Microsoft.DotNet.ProjectModel
RuntimeIdentifier = runtimeIdentifier; RuntimeIdentifier = runtimeIdentifier;
PackagesDirectory = packagesDirectory; PackagesDirectory = packagesDirectory;
LibraryManager = libraryManager; LibraryManager = libraryManager;
LockFile = lockfile;
} }
public LibraryExporter CreateExporter(string configuration) public LibraryExporter CreateExporter(string configuration)

View file

@ -259,7 +259,8 @@ namespace Microsoft.DotNet.ProjectModel
TargetFramework, TargetFramework,
target?.RuntimeIdentifier, target?.RuntimeIdentifier,
PackagesDirectory, PackagesDirectory,
libraryManager); libraryManager,
LockFile);
} }
private void ResolveDependencies(Dictionary<LibraryKey, LibraryDescription> libraries, private void ResolveDependencies(Dictionary<LibraryKey, LibraryDescription> libraries,

View file

@ -58,9 +58,9 @@ namespace Microsoft.DotNet.Tools.Build
{ {
if (incremental) if (incremental)
{ {
var dependencyContext = ProjectContext.Create(dependency.Path, dependency.Framework); var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework);
if (!NeedsRebuilding(dependencyContext, new ProjectDependenciesFacade(dependencyContext, _args.ConfigValue))) if (!NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue)))
{ {
continue; continue;
} }
@ -93,7 +93,7 @@ namespace Microsoft.DotNet.Tools.Build
// rebuild if empty inputs / outputs // rebuild if empty inputs / outputs
if (!(compilerIO.Outputs.Any() && compilerIO.Inputs.Any())) if (!(compilerIO.Outputs.Any() && compilerIO.Inputs.Any()))
{ {
Reporter.Verbose.WriteLine($"\nProject {project.ProjectName()} will be compiled because it either has empty inputs or outputs"); Reporter.Output.WriteLine($"\nProject {project.ProjectName()} will be compiled because it either has empty inputs or outputs");
return true; return true;
} }
@ -123,11 +123,11 @@ namespace Microsoft.DotNet.Tools.Build
if (!newInputs.Any()) if (!newInputs.Any())
{ {
Reporter.Verbose.WriteLine($"\nSkipped compilation for project {project.ProjectName()}. All the input files were older than the output files."); Reporter.Output.WriteLine($"\nProject {project.ProjectName()} was previoulsy compiled. Skipping compilation.");
return false; return false;
} }
Reporter.Verbose.WriteLine($"\nProject {project.ProjectName()} was compiled because some of its inputs were newer than its oldest output:"); Reporter.Output.WriteLine($"\nProject {project.ProjectName()} will be compiled because some of its inputs were newer than its oldest output.");
Reporter.Verbose.WriteLine($"Oldest output item was written at {minDate} : {minOutputPath}"); Reporter.Verbose.WriteLine($"Oldest output item was written at {minDate} : {minOutputPath}");
Reporter.Verbose.WriteLine($"Inputs newer than the oldest output item:"); Reporter.Verbose.WriteLine($"Inputs newer than the oldest output item:");
@ -148,14 +148,14 @@ namespace Microsoft.DotNet.Tools.Build
return false; return false;
} }
Reporter.Verbose.WriteLine($"\nProject {project.ProjectName()} will be compiled because expected {itemsType} are missing: "); Reporter.Output.WriteLine($"\nProject {project.ProjectName()} will be compiled because expected {itemsType} are missing. ");
foreach (var missing in missingItems) foreach (var missing in missingItems)
{ {
Reporter.Verbose.WriteLine($"\t {missing}"); Reporter.Verbose.WriteLine($"\t {missing}");
} }
Reporter.Verbose.WriteLine(); Reporter.Output.WriteLine();
return true; return true;
} }
@ -338,23 +338,26 @@ namespace Microsoft.DotNet.Tools.Build
public static CompilerIO GetCompileIO(ProjectContext project, string config, string outputPath, string intermediaryOutputPath, ProjectDependenciesFacade dependencies) public static CompilerIO GetCompileIO(ProjectContext project, string config, string outputPath, string intermediaryOutputPath, ProjectDependenciesFacade dependencies)
{ {
var compilerIO = new CompilerIO(new List<string>(), new List<string>()); var compilerIO = new CompilerIO(new List<string>(), new List<string>());
var compilationOutput = CompilerUtil.GetCompilationOutput(project.ProjectFile, project.TargetFramework, config, outputPath);
// input: project.json // input: project.json
compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath); compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);
// input: lock file; find when dependencies change
AddLockFile(project, compilerIO);
// input: source files // input: source files
compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project)); compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project));
// todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile
// todo: use lock file insteaf of dependencies. One file vs many
// input: dependencies // input: dependencies
AddDependencies(dependencies, compilerIO); AddDependencies(dependencies, compilerIO);
// input: key file
AddKeyFile(project, config, compilerIO);
// output: compiler output // output: compiler output
compilerIO.Outputs.Add(CompilerUtil.GetCompilationOutput(project.ProjectFile, project.TargetFramework, config, outputPath)); compilerIO.Outputs.Add(compilationOutput);
// input / output: compilation options files
AddFilesFromCompilationOptions(project, config, compilationOutput, compilerIO);
// input / output: resources without culture // input / output: resources without culture
AddCultureResources(project, intermediaryOutputPath, compilerIO); AddCultureResources(project, intermediaryOutputPath, compilerIO);
@ -365,22 +368,43 @@ namespace Microsoft.DotNet.Tools.Build
return compilerIO; return compilerIO;
} }
private static void AddLockFile(ProjectContext project, CompilerIO compilerIO)
{
if(project.LockFile == null)
{
var errorMessage = $"Project {project.ProjectName()} does not have a lock file.";
Reporter.Error.WriteLine(errorMessage);
throw new InvalidOperationException(errorMessage);
}
compilerIO.Inputs.Add(project.LockFile.LockFilePath);
}
private static void AddDependencies(ProjectDependenciesFacade dependencies, CompilerIO compilerIO) private static void AddDependencies(ProjectDependenciesFacade dependencies, CompilerIO compilerIO)
{ {
// add dependency sources that need compilation // add dependency sources that need compilation
compilerIO.Inputs.AddRange(dependencies.ProjectDependenciesWithSources.Values.SelectMany(p => p.Project.Files.SourceFiles)); compilerIO.Inputs.AddRange(dependencies.ProjectDependenciesWithSources.Values.SelectMany(p => p.Project.Files.SourceFiles));
// add compilation binaries // non project dependencies get captured by changes in the lock file
compilerIO.Inputs.AddRange(dependencies.Dependencies.SelectMany(d => d.CompilationAssemblies.Select(ca => ca.ResolvedPath)));
} }
private static void AddKeyFile(ProjectContext project, string config, CompilerIO compilerIO) private static void AddFilesFromCompilationOptions(ProjectContext project, string config, string compilationOutput, CompilerIO compilerIO)
{ {
var keyFile = CompilerUtil.ResolveCompilationOptions(project, config).KeyFile; var compilerOptions = CompilerUtil.ResolveCompilationOptions(project, config);
if (keyFile != null) // output: pdb file. They are always emitted (see compiler.csc)
compilerIO.Outputs.Add(Path.ChangeExtension(compilationOutput, "pdb"));
// output: documentation file
if (compilerOptions.GenerateXmlDocumentation == true)
{ {
compilerIO.Inputs.Add(keyFile); compilerIO.Outputs.Add(Path.ChangeExtension(compilationOutput, "xml"));
}
// input: key file
if (compilerOptions.KeyFile != null)
{
compilerIO.Inputs.Add(compilerOptions.KeyFile);
} }
} }

View file

@ -152,9 +152,10 @@ namespace Microsoft.DotNet.Tools.Compiler
return compilationOptions; return compilationOptions;
} }
//used in incremental precondition checks
public static IEnumerable<string> GetCommandsInvokedByCompile(ProjectContext project) public static IEnumerable<string> GetCommandsInvokedByCompile(ProjectContext project)
{ {
return new List<string> {ResolveCompilerName(project)}; return new List<string> {ResolveCompilerName(project), "dotnet-compile"};
} }
} }
} }

View file

@ -45,7 +45,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName()); TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
} }
[Fact] [Fact]
@ -56,13 +56,13 @@ namespace Microsoft.DotNet.Tests.EndToEnd
// first build // first build
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory); var buildCommand = new BuildCommand(TestProject, output: OutputDirectory);
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName()); TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
var latestWriteTimeFirstBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory); var latestWriteTimeFirstBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
// second build; should get skipped (incremental because no inputs changed) // second build; should get skipped (incremental because no inputs changed)
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName()); TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
var latestWriteTimeSecondBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory); var latestWriteTimeSecondBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
Assert.Equal(latestWriteTimeFirstBuild, latestWriteTimeSecondBuild); Assert.Equal(latestWriteTimeFirstBuild, latestWriteTimeSecondBuild);
@ -71,68 +71,12 @@ namespace Microsoft.DotNet.Tests.EndToEnd
// third build; should get compiled because the source file got touched // third build; should get compiled because the source file got touched
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName()); TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
var latestWriteTimeThirdBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory); var latestWriteTimeThirdBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
Assert.NotEqual(latestWriteTimeSecondBuild, latestWriteTimeThirdBuild); Assert.NotEqual(latestWriteTimeSecondBuild, latestWriteTimeThirdBuild);
} }
[Fact]
public void TestDotnetForceIncrementalUnsafe()
{
TestSetup();
// first build
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory);
buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName());
var latestWriteTimeFirstBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
// second build; will get recompiled due to force unsafe flag
buildCommand = new BuildCommand(TestProject, output: OutputDirectory, forceIncrementalUnsafe:true);
buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName());
var latestWriteTimeSecondBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
Assert.NotEqual(latestWriteTimeFirstBuild, latestWriteTimeSecondBuild);
}
[Fact]
public void TestDotnetIncrementalBuildDeleteOutputFile()
{
TestSetup();
// first build
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory);
buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName());
var latestWriteTimeFirstBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
Reporter.Verbose.WriteLine($"Files in {OutputDirectory}");
foreach (var file in Directory.EnumerateFiles(OutputDirectory))
{
Reporter.Verbose.Write($"\t {file}");
}
// delete output files
foreach (var outputFile in Directory.EnumerateFiles(OutputDirectory).Where(f => Path.GetFileName(f).StartsWith(s_testdirName, StringComparison.OrdinalIgnoreCase)))
{
Reporter.Verbose.WriteLine($"Delete {outputFile}");
File.Delete(outputFile);
Assert.False(File.Exists(outputFile));
}
// second build; should get rebuilt since we deleted output items
buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName());
var latestWriteTimeSecondBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
Assert.NotEqual(latestWriteTimeFirstBuild, latestWriteTimeSecondBuild);
}
[Fact] [Fact]
[ActiveIssue(712, PlatformID.Windows | PlatformID.OSX | PlatformID.Linux)] [ActiveIssue(712, PlatformID.Windows | PlatformID.OSX | PlatformID.Linux)]
public void TestDotnetBuildNativeRyuJit() public void TestDotnetBuildNativeRyuJit()
@ -148,7 +92,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
var nativeOut = Path.Combine(OutputDirectory, "native"); var nativeOut = Path.Combine(OutputDirectory, "native");
TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName()); TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName(), s_expectedOutput);
} }
[Fact] [Fact]
@ -165,7 +109,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
var nativeOut = Path.Combine(OutputDirectory, "native"); var nativeOut = Path.Combine(OutputDirectory, "native");
TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName()); TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName(), s_expectedOutput);
} }
[Fact] [Fact]
@ -182,13 +126,13 @@ namespace Microsoft.DotNet.Tests.EndToEnd
// first build // first build
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true); var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true);
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName()); TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName(), s_expectedOutput);
var latestWriteTimeFirstBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory); var latestWriteTimeFirstBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
// second build; should be skipped because nothing changed // second build; should be skipped because nothing changed
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName()); TestOutputExecutable(nativeOut, buildCommand.GetOutputExecutableName(), s_expectedOutput);
var latestWriteTimeSecondBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory); var latestWriteTimeSecondBuild = GetLastWriteTimeOfDirectoryFiles(OutputDirectory);
Assert.Equal(latestWriteTimeFirstBuild, latestWriteTimeSecondBuild); Assert.Equal(latestWriteTimeFirstBuild, latestWriteTimeSecondBuild);
@ -220,7 +164,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
var publishCommand = new PublishCommand(TestProject, output: OutputDirectory); var publishCommand = new PublishCommand(TestProject, output: OutputDirectory);
publishCommand.Execute().Should().Pass(); publishCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, publishCommand.GetOutputExecutable()); TestOutputExecutable(OutputDirectory, publishCommand.GetOutputExecutable(), s_expectedOutput);
} }
private void TestSetup() private void TestSetup()
@ -245,19 +189,6 @@ namespace Microsoft.DotNet.Tests.EndToEnd
Directory.SetCurrentDirectory(currentDirectory); Directory.SetCurrentDirectory(currentDirectory);
} }
private void TestOutputExecutable(string outputDir, string executableName)
{
var executablePath = Path.Combine(outputDir, executableName);
var executableCommand = new TestCommand(executablePath);
var result = executableCommand.ExecuteWithCapturedOutput("");
result.Should().HaveStdOut(s_expectedOutput);
result.Should().NotHaveStdErr();
result.Should().Pass();
}
private bool IsCentOS() private bool IsCentOS()
{ {
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))

View file

@ -0,0 +1,81 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
namespace Microsoft.DotNet.Tools.Builder.Tests
{
public class ProjectToProjectDependenciesIncrementalTest : IncrementalTestBase
{
private string[] _projects = new[] { "L0", "L11", "L12", "L21", "L22" };
private string _testProjectsRoot = @"TestProjects";
private string _testProject = "TestProjectToProjectDependencies";
private TempDirectory tempProjectRoot;
public ProjectToProjectDependenciesIncrementalTest() : base(
Path.Combine("TestProjects", "TestProjectToProjectDependencies"),
"L0",
"L0 L11 L12 L22 L21 L12 L22 " + Environment.NewLine)
{
}
[Theory,
InlineData("L0", new[] { "L0" }),
InlineData("L11", new[] { "L0", "L11" }),
InlineData("L12", new[] { "L0", "L11", "L12" }),
InlineData("L22", new[] { "L0", "L11", "L12", "L22" }),
InlineData("L21", new[] { "L0", "L11", "L21" })
]
public void TestIncrementalBuildOfDependencyGraph(string projectToTouch, string[] expectedRebuiltProjects)
{
// first clean build; all projects required compilation
var result1 = BuildProject();
AssertRebuilt(result1, _projects);
// second build; nothing changed; no project required compilation
var result2 = BuildProject();
AssertRebuilt(result2, Array.Empty<string>());
//modify the source code of a project
TouchSourcesOfProject(projectToTouch);
// third build; all projects on the paths from touched project to root project need to be rebuilt
var result3 = BuildProject();
AssertRebuilt(result3, expectedRebuiltProjects);
}
// compute A - B
private T[] SetDifference<T>(T[] A, T[] B)
{
var setA = new HashSet<T>(A);
setA.ExceptWith(B);
return setA.ToArray();
}
private void AssertRebuilt(CommandResult buildResult, string[] expectedRebuilt)
{
foreach (var rebuiltProject in expectedRebuilt)
{
AssertProjectCompiled(rebuiltProject, buildResult);
}
foreach (var skippedProject in SetDifference(_projects, expectedRebuilt))
{
AssertProjectSkipped(skippedProject, buildResult);
}
}
protected override string GetProjectDirectory(string projectName)
{
return Path.Combine(_tempProjectRoot.Path, "src", projectName);
}
}
}

View file

@ -0,0 +1,118 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
namespace Microsoft.DotNet.Tools.Builder.Tests
{
public class IncrementalTestBase : TestBase
{
protected readonly TempDirectory _tempProjectRoot;
private readonly string _testProjectsRoot;
protected readonly string _mainProject;
protected readonly string _expectedOutput;
public IncrementalTestBase(string testProjectsRoot, string mainProject, string expectedOutput)
{
_testProjectsRoot = testProjectsRoot;
_mainProject = mainProject;
_expectedOutput = expectedOutput;
// create unique directories in the 'temp' folder
var root = Temp.CreateDirectory();
// recursively copy projects to the temp dir and restore them
_tempProjectRoot = root.CopyDirectory(testProjectsRoot);
RunRestore(_tempProjectRoot.Path);
}
protected void TouchSourcesOfProject()
{
TouchSourcesOfProject(_mainProject);
}
protected void TouchSourcesOfProject(string projectToTouch)
{
foreach (var sourceFile in GetSourceFilesForProject(projectToTouch))
{
TouchFile(sourceFile);
}
}
protected static void TouchFile(string file)
{
File.SetLastWriteTimeUtc(file, DateTime.UtcNow);
}
protected CommandResult BuildProject(bool forceIncrementalUnsafe = false, bool expectBuildFailure = false)
{
var outputDir = GetBinDirectory();
var intermediateOutputDir = Path.Combine(Directory.GetParent(outputDir).FullName, "obj", _mainProject);
var mainProjectFile = GetProjectFile(_mainProject);
var buildCommand = new BuildCommand(mainProjectFile, output: outputDir, tempOutput: intermediateOutputDir ,forceIncrementalUnsafe : forceIncrementalUnsafe);
var result = buildCommand.ExecuteWithCapturedOutput();
if (!expectBuildFailure)
{
result.Should().Pass();
TestOutputExecutable(outputDir, buildCommand.GetOutputExecutableName(), _expectedOutput);
}
else
{
result.Should().Fail();
}
return result;
}
protected static void AssertProjectSkipped(string skippedProject, CommandResult buildResult)
{
Assert.Contains($"Project {skippedProject} was previoulsy compiled. Skipping compilation.", buildResult.StdOut);
}
protected static void AssertProjectCompiled(string rebuiltProject, CommandResult buildResult)
{
Assert.Contains($"Project {rebuiltProject} will be compiled", buildResult.StdOut, StringComparison.OrdinalIgnoreCase);
}
protected string GetBinDirectory()
{
return Path.Combine(_tempProjectRoot.Path, "bin");
}
protected virtual string GetProjectDirectory(string projectName)
{
return Path.Combine(_tempProjectRoot.Path);
}
protected string GetProjectFile(string projectName)
{
return Path.Combine(GetProjectDirectory(projectName), "project.json");
}
private string GetOutputFileForProject(string projectName)
{
return Path.Combine(GetBinDirectory(), projectName + ".dll");
}
private IEnumerable<string> GetSourceFilesForProject(string projectName)
{
return Directory.EnumerateFiles(GetProjectDirectory(projectName)).
Where(f => f.EndsWith(".cs"));
}
private void RunRestore(string args)
{
var restoreCommand = new RestoreCommand();
restoreCommand.Execute($"--quiet {args}").Should().Pass();
}
}
}

View file

@ -0,0 +1,130 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
namespace Microsoft.DotNet.Tools.Builder.Tests
{
public class IncrementalTests : IncrementalTestBase
{
private string _testProjectsRoot = @"TestProjects";
private string _testProject = "TestProjectToProjectDependencies";
private TempDirectory tempProjectRoot;
public IncrementalTests() : base(
Path.Combine("TestProjects", "TestSimpleIncrementalApp"),
"TestSimpleIncrementalApp",
"Hello World!" + Environment.NewLine)
{
}
[Fact]
public void TestForceIncrementalUnsafe()
{
var buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
buildResult = BuildProject(forceIncrementalUnsafe: true);
Assert.Contains("[Forced Unsafe]", buildResult.StdOut);
}
[Fact]
public void TestRebuildMissingPdb()
{
TestDeleteOutputWithExtension("pdb");
}
[Fact]
public void TestRebuildMissingDll()
{
TestDeleteOutputWithExtension("dll");
}
[Fact]
public void TestRebuildMissingXml()
{
TestDeleteOutputWithExtension("xml");
}
[Fact]
public void TestNoLockFile()
{
var buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
var lockFile = Path.Combine(_tempProjectRoot.Path, "project.lock.json");
Assert.True(File.Exists(lockFile));
File.Delete(lockFile);
Assert.False(File.Exists(lockFile));
buildResult = BuildProject(expectBuildFailure : true);
Assert.Contains("does not have a lock file", buildResult.StdErr);
}
[Fact]
public void TestRebuildChangedLockFile()
{
var buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
var lockFile = Path.Combine(_tempProjectRoot.Path, "project.lock.json");
TouchFile(lockFile);
buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
}
[Fact]
public void TestRebuildChangedProjectFile()
{
var buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
TouchFile(GetProjectFile(_mainProject));
buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
}
private void TestDeleteOutputWithExtension(string extension)
{
var buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
Reporter.Verbose.WriteLine($"Files in {GetBinDirectory()}");
foreach (var file in Directory.EnumerateFiles(GetBinDirectory()))
{
Reporter.Verbose.Write($"\t {file}");
}
// delete output files with extensions
foreach (var outputFile in Directory.EnumerateFiles(GetBinDirectory()).Where(f =>
{
var fileName = Path.GetFileName(f);
return fileName.StartsWith(_mainProject, StringComparison.OrdinalIgnoreCase) &&
fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase);
}))
{
Reporter.Output.WriteLine($"Deleted {outputFile}");
File.Delete(outputFile);
Assert.False(File.Exists(outputFile));
}
// second build; should get rebuilt since we deleted an output item
buildResult = BuildProject();
AssertProjectCompiled(_mainProject, buildResult);
}
}
}

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.23107" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.23107</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>833ffee1-7eed-4f51-8dfd-946d48833333</ProjectGuid>
<RootNamespace>Microsoft.DotNet.Tools.Builder.Tests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View file

@ -0,0 +1,23 @@
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23704",
"Microsoft.NETCore.TestHost" : "1.0.0-*",
"xunit": "2.1.0",
"xunit.console.netcore": "1.0.2-prerelease-00101",
"xunit.netcore.extensions": "1.0.0-prerelease-*",
"xunit.runner.utility": "2.1.0",
"Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" },
"Microsoft.DotNet.Cli.Utils": {
"target": "project",
"type": "build"
}
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -201,7 +201,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
public override CommandResult ExecuteWithCapturedOutput(string args = "") public override CommandResult ExecuteWithCapturedOutput(string args = "")
{ {
args = $"build {BuildArgs()} {args}"; args = $"--verbose build {BuildArgs()} {args}";
return base.ExecuteWithCapturedOutput(args); return base.ExecuteWithCapturedOutput(args);
} }

View file

@ -69,6 +69,31 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
File.Copy(originalPath, filePath); File.Copy(originalPath, filePath);
return _root.AddFile(new DisposableFile(filePath)); return _root.AddFile(new DisposableFile(filePath));
} }
/// <summary>
/// Recursively copy the provided directory into this TempDirectory.
/// Does not handle links.
/// </summary>
/// <param name="sourceDirectory"></param>
/// <returns></returns>
public TempDirectory CopyDirectory(string sourceDirectory)
{
Debug.Assert(Directory.Exists(sourceDirectory));
var tempCopy = CreateDirectory(new DirectoryInfo(sourceDirectory).Name);
foreach(var file in Directory.EnumerateFiles(sourceDirectory))
{
tempCopy.CopyFile(file);
}
foreach(var directory in Directory.EnumerateDirectories(sourceDirectory))
{
tempCopy.CopyDirectory(directory);
}
return tempCopy;
}
/// <summary> /// <summary>
/// Creates a subdirectory in this directory. /// Creates a subdirectory in this directory.

View file

@ -3,8 +3,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Test.Utilities namespace Microsoft.DotNet.Tools.Test.Utilities
{ {
@ -55,5 +57,18 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
string.Equals("1", val, StringComparison.OrdinalIgnoreCase) || string.Equals("1", val, StringComparison.OrdinalIgnoreCase) ||
string.Equals("on", val, StringComparison.OrdinalIgnoreCase)); string.Equals("on", val, StringComparison.OrdinalIgnoreCase));
} }
protected void TestOutputExecutable(string outputDir, string executableName, string expectedOutput)
{
var executablePath = Path.Combine(outputDir, executableName);
var executableCommand = new TestCommand(executablePath);
var result = executableCommand.ExecuteWithCapturedOutput("");
result.Should().HaveStdOut(expectedOutput);
result.Should().NotHaveStdErr();
result.Should().Pass();
}
} }
} }

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>947dd232-8d9b-4b78-9c6a-94f807d22222</ProjectGuid>
<RootNamespace>TestProjectToProjectDependencies</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View file

@ -0,0 +1,3 @@
{
"projects": [ "src" ]
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="dotnet-core" value="https://www.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View file

@ -0,0 +1,12 @@
using System;
namespace ConsoleApplication
{
public class L0
{
public static void Main(string[] args)
{
Console.WriteLine("L0 " + L11.Value() + L12.Value());
}
}
}

View file

@ -0,0 +1,17 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"L11": "1.0.0-*",
"L12": "1.0.0-*",
"NETStandard.Library": "1.0.0-rc2-23704"
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="dotnet-core" value="https://www.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View file

@ -0,0 +1,12 @@
using System;
namespace ConsoleApplication
{
public class L11
{
public static string Value()
{
return "L11 " + L12.Value() + L21.Value();
}
}
}

View file

@ -0,0 +1,14 @@
{
"version": "1.0.0-*",
"dependencies": {
"L12": "1.0.0-*",
"L21": "1.0.0-*",
"NETStandard.Library": "1.0.0-rc2-23704"
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="dotnet-core" value="https://www.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View file

@ -0,0 +1,12 @@
using System;
namespace ConsoleApplication
{
public class L12
{
public static string Value()
{
return "L12 " + L22.Value();
}
}
}

View file

@ -0,0 +1,13 @@
{
"version": "1.0.0-*",
"dependencies": {
"L22": "1.0.0-*",
"NETStandard.Library": "1.0.0-rc2-23704"
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="dotnet-core" value="https://www.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View file

@ -0,0 +1,12 @@
using System;
namespace ConsoleApplication
{
public class L21
{
public static string Value()
{
return "L21 ";
}
}
}

View file

@ -0,0 +1,11 @@
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23704"
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="dotnet-core" value="https://www.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View file

@ -0,0 +1,12 @@
using System;
namespace ConsoleApplication
{
public class L22
{
public static string Value()
{
return "L22 ";
}
}
}

View file

@ -0,0 +1,11 @@
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23704"
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="dotnet-core" value="https://www.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View file

@ -0,0 +1,12 @@
using System;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>58808bbc-371e-47d6-a3d0-4902145edaaa</ProjectGuid>
<RootNamespace>TestSimpleIncrementalApp</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View file

@ -0,0 +1,15 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true,
"xmlDoc": true
},
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23704"
},
"frameworks": {
"dnxcore50": { }
}
}