Update dotnet-build to produce portable layout
dotnet-build will produce a deps file for portable builds, and will now create "runnable" outputs for RID-less targets the outputs won't actually be runnable today because we need corehost changes and to generate a deps.json file for corehost to use.
This commit is contained in:
parent
444e4f9fd7
commit
7cc90d9ad1
22 changed files with 334 additions and 99 deletions
3
TestAssets/TestProjects/BuildTestPortableProject/Lib.cs
Normal file
3
TestAssets/TestProjects/BuildTestPortableProject/Lib.cs
Normal file
|
@ -0,0 +1,3 @@
|
|||
public static class Thingy
|
||||
{
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"dependencies": {
|
||||
},
|
||||
"frameworks": {
|
||||
"net45": {},
|
||||
"netstandardapp1.5": {
|
||||
"imports": [
|
||||
"dnxcore50",
|
||||
"portable-net45+win8"
|
||||
],
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23901"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
public static class Thingy
|
||||
{
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"dependencies": { },
|
||||
"frameworks": {
|
||||
"netstandardapp1.5": {
|
||||
"imports": [
|
||||
"dnxcore50",
|
||||
"portable-net45+win8"
|
||||
],
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23901"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runtimes": {
|
||||
"win7-x64": {},
|
||||
"osx.10.10-x64": {},
|
||||
"ubuntu.14.04-x64": {},
|
||||
"centos.7-x64": {}
|
||||
}
|
||||
}
|
|
@ -6,11 +6,16 @@
|
|||
$oldPath = $env:PATH
|
||||
try {
|
||||
# Put the stage2 output on the front of the path
|
||||
$stage2 = "$PSScriptRoot\..\artifacts\win7-x64\stage2\bin"
|
||||
if(!(Get-Command dotnet -ErrorAction SilentlyContinue)) {
|
||||
throw "You need to have a version of 'dotnet' on your path so we can determine the RID"
|
||||
}
|
||||
|
||||
$rid = dotnet --version | where { $_ -match "^ Runtime Id:\s*(.*)$" } | foreach { $matches[1] }
|
||||
$stage2 = "$PSScriptRoot\..\artifacts\$rid\stage2\bin"
|
||||
if (Test-Path $stage2) {
|
||||
$env:PATH="$stage2;$env:PATH"
|
||||
} else {
|
||||
Write-Host "You don't have a dev build in the 'artifacts\win7-x64\stage2' folder!"
|
||||
Write-Host "You don't have a dev build in the 'artifacts\$rid\stage2' folder!"
|
||||
}
|
||||
|
||||
dotnet @args
|
||||
|
|
|
@ -45,6 +45,13 @@ namespace Microsoft.DotNet.Cli.Build
|
|||
"Microsoft.Extensions.Testing.Abstractions"
|
||||
};
|
||||
|
||||
// Updates the stage 2 with recent changes.
|
||||
[Target(nameof(PrepareTargets.Init), nameof(CompileStage2))]
|
||||
public static BuildTargetResult UpdateBuild(BuildTargetContext c)
|
||||
{
|
||||
return c.Success();
|
||||
}
|
||||
|
||||
[Target(nameof(PrepareTargets.Init), nameof(CompileCoreHost), nameof(CompileStage1), nameof(CompileStage2))]
|
||||
public static BuildTargetResult Compile(BuildTargetContext c)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
"netstandard1.3": {
|
||||
"imports": "dnxcore50",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23901"
|
||||
"NETStandard.Library": "1.0.0-rc2-23901",
|
||||
"System.Diagnostics.Process": "4.1.0-rc2-23901"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,11 +39,6 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
|
||||
public void MakeCompilationOutputRunnable()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_context.RuntimeIdentifier))
|
||||
{
|
||||
throw new InvalidOperationException($"Can not make output runnable for framework {_context.TargetFramework}, because it doesn't have runtime target");
|
||||
}
|
||||
|
||||
CopyContentFiles();
|
||||
ExportRuntimeAssets();
|
||||
}
|
||||
|
@ -72,9 +67,12 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
|
|||
{
|
||||
WriteDepsFileAndCopyProjectDependencies(_exporter);
|
||||
|
||||
if (!string.IsNullOrEmpty(_context.RuntimeIdentifier))
|
||||
{
|
||||
// TODO: Pick a host based on the RID
|
||||
CoreHost.CopyTo(_runtimeOutputPath, _context.ProjectFile.Name + Constants.ExeSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyContentFiles()
|
||||
{
|
||||
|
|
|
@ -50,6 +50,12 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
runtimeOutputPath = PathUtility.EnsureTrailingSlash(Path.Combine(compilationOutputPath, runtimeIdentifier));
|
||||
}
|
||||
else
|
||||
{
|
||||
// "Runtime" assets (i.e. the deps file) will be dropped to the compilation output path, because
|
||||
// we are building a RID-less target.
|
||||
runtimeOutputPath = compilationOutputPath;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -124,12 +124,12 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
|
||||
public bool HasRuntimeOutput(string configuration)
|
||||
{
|
||||
|
||||
var compilationOptions = GetCompilerOptions(targetFramework: null, configurationName: configuration);
|
||||
|
||||
// TODO: Make this opt in via another mechanism
|
||||
return compilationOptions.EmitEntryPoint.GetValueOrDefault() || IsTestProject;
|
||||
}
|
||||
|
||||
private CommonCompilerOptions GetCompilerOptions()
|
||||
{
|
||||
return _defaultCompilerOptions;
|
||||
|
|
|
@ -120,15 +120,12 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
/// <summary>
|
||||
/// Creates a project context for each target located in the project at <paramref name="projectPath"/>
|
||||
/// </summary>
|
||||
public static IEnumerable<ProjectContext> CreateContextForEachTarget(string projectPath)
|
||||
public static IEnumerable<ProjectContext> CreateContextForEachTarget(string projectPath, ProjectReaderSettings settings = null)
|
||||
{
|
||||
if (!projectPath.EndsWith(Project.FileName))
|
||||
{
|
||||
projectPath = Path.Combine(projectPath, Project.FileName);
|
||||
}
|
||||
var project = ProjectReader.GetProject(projectPath);
|
||||
|
||||
return new ProjectContextBuilder()
|
||||
.WithReaderSettings(settings)
|
||||
.WithProject(project)
|
||||
.BuildAllTargets();
|
||||
}
|
||||
|
@ -143,15 +140,20 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
|
||||
public ProjectContext CreateRuntimeContext(IEnumerable<string> runtimeIdentifiers)
|
||||
{
|
||||
var context = Create(ProjectFile.ProjectFilePath, TargetFramework, runtimeIdentifiers);
|
||||
if (context.RuntimeIdentifier == null)
|
||||
// Check if there are any runtime targets (i.e. are we portable)
|
||||
var standalone = LockFile.Targets
|
||||
.Where(t => t.TargetFramework.Equals(TargetFramework))
|
||||
.Any(t => !string.IsNullOrEmpty(t.RuntimeIdentifier));
|
||||
|
||||
var context = Create(ProjectFile.ProjectFilePath, TargetFramework, standalone ? runtimeIdentifiers : Enumerable.Empty<string>());
|
||||
if (standalone && context.RuntimeIdentifier == null)
|
||||
{
|
||||
// We are standalone, but don't support this runtime
|
||||
var rids = string.Join(", ", runtimeIdentifiers);
|
||||
throw new InvalidOperationException($"Can not find runtime target for framework '{TargetFramework}' and RID's '{rids}'. " +
|
||||
throw new InvalidOperationException($"Can not find runtime target for framework '{TargetFramework}' compatible with one of the target runtimes: '{rids}'. " +
|
||||
"Possible causes:" + Environment.NewLine +
|
||||
"1. Project is not restored or restore failed - run `dotnet restore`" + Environment.NewLine +
|
||||
"2. Project is not targeting `runable` framework (`netstandardapp*` or `net*`)"
|
||||
);
|
||||
"1. The project has not been restored or restore failed - run `dotnet restore`" + Environment.NewLine +
|
||||
$"2. The project does not list one of '{rids}' in the 'runtimes' section.");
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
|
|
@ -61,18 +61,20 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
return true;
|
||||
}
|
||||
|
||||
public static Project GetProject(string projectFile, ProjectReaderSettings settings = null)
|
||||
public static Project GetProject(string projectPath, ProjectReaderSettings settings = null) => GetProject(projectPath, new List<DiagnosticMessage>(), settings);
|
||||
|
||||
public static Project GetProject(string projectPath, ICollection<DiagnosticMessage> diagnostics, ProjectReaderSettings settings = null)
|
||||
{
|
||||
return GetProject(projectFile, new List<DiagnosticMessage>(), settings);
|
||||
if (!projectPath.EndsWith(Project.FileName))
|
||||
{
|
||||
projectPath = Path.Combine(projectPath, Project.FileName);
|
||||
}
|
||||
|
||||
public static Project GetProject(string projectFile, ICollection<DiagnosticMessage> diagnostics, ProjectReaderSettings settings = null)
|
||||
{
|
||||
var name = Path.GetFileName(Path.GetDirectoryName(projectFile));
|
||||
var name = Path.GetFileName(Path.GetDirectoryName(projectPath));
|
||||
|
||||
using (var stream = new FileStream(projectFile, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (var stream = new FileStream(projectPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return new ProjectReader().ReadProject(stream, name, projectFile, diagnostics, settings);
|
||||
return new ProjectReader().ReadProject(stream, name, projectPath, diagnostics, settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,7 +548,8 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
analyzerOptions.LanguageId = languageId;
|
||||
break;
|
||||
|
||||
default:;
|
||||
default:
|
||||
;
|
||||
throw FileFormatException.Create(
|
||||
$"Unrecognized analyzerOption key: {key}",
|
||||
project.ProjectFilePath);
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
{
|
||||
CreateOutputDirectories();
|
||||
|
||||
return CompileDendencies(incremental) && CompileRootProject(incremental);
|
||||
return CompileDependencies(incremental) && CompileRootProject(incremental);
|
||||
}
|
||||
|
||||
private bool CompileRootProject(bool incremental)
|
||||
|
@ -66,7 +66,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
return success;
|
||||
}
|
||||
|
||||
private bool CompileDendencies(bool incremental)
|
||||
private bool CompileDependencies(bool incremental)
|
||||
{
|
||||
if (_args.ShouldSkipDependencies)
|
||||
{
|
||||
|
@ -394,17 +394,9 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
var succeeded = compileResult == 0;
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
if (_rootProject.ProjectFile.HasRuntimeOutput(_args.ConfigValue))
|
||||
{
|
||||
MakeRunnable();
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(_args.OutputValue))
|
||||
{
|
||||
var outputPaths = _rootProject.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
|
||||
CopyCompilationOutput(outputPaths);
|
||||
}
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
@ -428,9 +420,22 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
private void MakeRunnable()
|
||||
{
|
||||
var runtimeContext = _rootProject.CreateRuntimeContext(_args.GetRuntimes());
|
||||
if(_args.PortableMode)
|
||||
{
|
||||
// HACK: Force the use of the portable target
|
||||
runtimeContext = _rootProject;
|
||||
}
|
||||
|
||||
var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
|
||||
var libraryExporter = runtimeContext.CreateExporter(_args.ConfigValue, _args.BuildBasePathValue);
|
||||
|
||||
// If we're building for a specific RID, we need to copy the RID-less compilation output into
|
||||
// the RID-specific output dir
|
||||
if (!string.IsNullOrEmpty(runtimeContext.RuntimeIdentifier))
|
||||
{
|
||||
CopyCompilationOutput(outputPaths);
|
||||
}
|
||||
|
||||
var executable = new Executable(runtimeContext, outputPaths, libraryExporter);
|
||||
executable.MakeCompilationOutputRunnable();
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
|
@ -28,6 +29,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
private CommandOption _runtimeOption;
|
||||
private CommandOption _versionSuffixOption;
|
||||
private CommandOption _configurationOption;
|
||||
private CommandOption _portableOption;
|
||||
private CommandArgument _projectArgument;
|
||||
private CommandOption _nativeOption;
|
||||
private CommandOption _archOption;
|
||||
|
@ -41,8 +43,8 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
// resolved values for the options and arguments
|
||||
public string ProjectPathValue { get; set; }
|
||||
public string BuildBasePathValue { get; set; }
|
||||
public string OutputValue { get; set; }
|
||||
public string RuntimeValue { get; set; }
|
||||
public string OutputValue { get; set; }
|
||||
public string VersionSuffixValue { get; set; }
|
||||
public string ConfigValue { get; set; }
|
||||
public bool IsNativeValue { get; set; }
|
||||
|
@ -53,6 +55,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
public bool IsCppModeValue { get; set; }
|
||||
public string AppDepSdkPathValue { get; set; }
|
||||
public string CppCompilerFlagsValue { get; set; }
|
||||
public bool PortableMode { get; set; }
|
||||
|
||||
// workaround: CommandLineApplication is internal therefore I cannot make _app protected so baseclasses can add their own params
|
||||
private readonly Dictionary<string, CommandOption> baseClassOptions;
|
||||
|
@ -77,12 +80,15 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
|
||||
_outputOption = _app.Option("-o|--output <OUTPUT_DIR>", "Directory in which to place outputs", CommandOptionType.SingleValue);
|
||||
_buildBasePath = _app.Option("-b|--build-base-path <OUTPUT_DIR>", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
|
||||
_frameworkOption = _app.Option("-f|--framework <FRAMEWORK>", "Compile a specific framework", CommandOptionType.MultipleValue);
|
||||
_frameworkOption = _app.Option("-f|--framework <FRAMEWORK>", "Compile a specific framework", CommandOptionType.SingleValue);
|
||||
_runtimeOption = _app.Option("-r|--runtime <RUNTIME_IDENTIFIER>", "Produce runtime-specific assets for the specified runtime", CommandOptionType.SingleValue);
|
||||
_configurationOption = _app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
|
||||
_runtimeOption = _app.Option("-r|--runtime <RUNTIME_IDENTIFIER>", "Target runtime to publish for", CommandOptionType.SingleValue);
|
||||
_versionSuffixOption = _app.Option("--version-suffix <VERSION_SUFFIX>", "Defines what `*` should be replaced with in version field in project.json", CommandOptionType.SingleValue);
|
||||
_projectArgument = _app.Argument("<PROJECT>", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory");
|
||||
|
||||
// HACK: Allow us to treat a project as though it was portable by ignoring the runtime-specific targets. This is temporary until RID inference is removed from NuGet
|
||||
_portableOption = _app.Option("--portable", "TEMPORARY: Enforces portable build/publish mode", CommandOptionType.NoValue);
|
||||
|
||||
// Native Args
|
||||
_nativeOption = _app.Option("-n|--native", "Compiles source to native machine code.", CommandOptionType.NoValue);
|
||||
_archOption = _app.Option("-a|--arch <ARCH>", "The architecture for which to compile. x64 only currently supported.", CommandOptionType.SingleValue);
|
||||
|
@ -98,6 +104,12 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
{
|
||||
_app.OnExecute(() =>
|
||||
{
|
||||
if (_outputOption.HasValue() && !_frameworkOption.HasValue())
|
||||
{
|
||||
Reporter.Error.WriteLine("When the '--output' option is provided, the '--framework' option must also be provided.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Locate the project and get the name and full path
|
||||
ProjectPathValue = _projectArgument.Value;
|
||||
if (string.IsNullOrEmpty(ProjectPathValue))
|
||||
|
@ -110,6 +122,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
ConfigValue = _configurationOption.Value() ?? Constants.DefaultConfiguration;
|
||||
RuntimeValue = _runtimeOption.Value();
|
||||
VersionSuffixValue = _versionSuffixOption.Value();
|
||||
PortableMode = _portableOption.HasValue();
|
||||
|
||||
IsNativeValue = _nativeOption.HasValue();
|
||||
ArchValue = _archOption.Value();
|
||||
|
@ -120,8 +133,6 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
IsCppModeValue = _cppModeOption.HasValue();
|
||||
CppCompilerFlagsValue = _cppCompilerFlagsOption.Value();
|
||||
|
||||
IEnumerable<ProjectContext> contexts;
|
||||
|
||||
// Set defaults based on the environment
|
||||
var settings = ProjectReaderSettings.ReadFromEnvironment();
|
||||
|
||||
|
@ -130,29 +141,35 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
settings.VersionSuffix = VersionSuffixValue;
|
||||
}
|
||||
|
||||
if (_frameworkOption.HasValue())
|
||||
// Load the project file and construct all the targets
|
||||
var targets = ProjectContext.CreateContextForEachFramework(ProjectPathValue, settings).ToList();
|
||||
|
||||
if (targets.Count == 0)
|
||||
{
|
||||
contexts = _frameworkOption.Values
|
||||
.Select(f =>
|
||||
{
|
||||
return ProjectContext.CreateBuilder(ProjectPathValue, NuGetFramework.Parse(f))
|
||||
.WithReaderSettings(settings)
|
||||
.Build();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(OutputValue))
|
||||
{
|
||||
throw new InvalidOperationException($"'{_frameworkOption.LongName}' is required when '{_outputOption.LongName}' is specified");
|
||||
}
|
||||
else
|
||||
{
|
||||
contexts = ProjectContext.CreateContextForEachFramework(ProjectPathValue, settings);
|
||||
}
|
||||
// Project is missing 'frameworks' section
|
||||
Reporter.Error.WriteLine("Project does not have any frameworks listed in the 'frameworks' section.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var success = execute(contexts.ToList(), this);
|
||||
// Filter the targets down based on the inputs
|
||||
if (_frameworkOption.HasValue())
|
||||
{
|
||||
var fx = NuGetFramework.Parse(_frameworkOption.Value());
|
||||
targets = targets.Where(t => fx.Equals(t.TargetFramework)).ToList();
|
||||
|
||||
if (targets.Count == 0)
|
||||
{
|
||||
// We filtered everything out
|
||||
Reporter.Error.WriteLine($"Project does not support framework: {fx.DotNetFrameworkName}.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Debug.Assert(targets.Count == 1);
|
||||
}
|
||||
|
||||
Debug.Assert(targets.All(t => string.IsNullOrEmpty(t.RuntimeIdentifier)));
|
||||
|
||||
var success = execute(targets, this);
|
||||
|
||||
return success ? 0 : 1;
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ using Microsoft.DotNet.Cli.Compiler.Common;
|
|||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
|
@ -161,6 +160,10 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
contextVariables.Add(
|
||||
"compile:RuntimeOutputDir",
|
||||
runtimeOutputPath.RuntimeOutputPath.TrimEnd('\\', '/'));
|
||||
|
||||
contextVariables.Add(
|
||||
"compile:RuntimeIdentifier",
|
||||
runtimeContext.RuntimeIdentifier);
|
||||
}
|
||||
|
||||
_scriptRunner.RunScripts(context, ScriptNames.PreCompile, contextVariables);
|
||||
|
|
|
@ -27,5 +27,5 @@
|
|||
|
||||
"testRunner": "xunit",
|
||||
|
||||
"scripts": { "precompile": "dotnet build ../ArgumentsReflector/project.json --framework netstandardapp1.5 --output %compile:RuntimeOutputDir%" }
|
||||
"scripts": { "precompile": "dotnet build ../ArgumentsReflector/project.json --framework netstandardapp1.5 --runtime %compile:RuntimeIdentifier% --output %compile:RuntimeOutputDir%" }
|
||||
}
|
||||
|
|
|
@ -60,7 +60,14 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
return new AndConstraint<CommandResultAssertions>(this);
|
||||
}
|
||||
|
||||
public AndConstraint<CommandResultAssertions> StdOutMatchPattern(string pattern, RegexOptions options = RegexOptions.None)
|
||||
public AndConstraint<CommandResultAssertions> HaveStdOutContaining(string pattern)
|
||||
{
|
||||
Execute.Assertion.ForCondition(_commandResult.StdOut.Contains(pattern))
|
||||
.FailWith(AppendDiagnosticsTo($"The command output did not contain expected result: {pattern}{Environment.NewLine}"));
|
||||
return new AndConstraint<CommandResultAssertions>(this);
|
||||
}
|
||||
|
||||
public AndConstraint<CommandResultAssertions> HaveStdOutMatching(string pattern, RegexOptions options = RegexOptions.None)
|
||||
{
|
||||
Execute.Assertion.ForCondition(Regex.Match(_commandResult.StdOut, pattern, options).Success)
|
||||
.FailWith(AppendDiagnosticsTo($"Matching the command output failed. Pattern: {pattern}{Environment.NewLine}"));
|
||||
|
@ -74,6 +81,20 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
return new AndConstraint<CommandResultAssertions>(this);
|
||||
}
|
||||
|
||||
public AndConstraint<CommandResultAssertions> HaveStdErrContaining(string pattern)
|
||||
{
|
||||
Execute.Assertion.ForCondition(_commandResult.StdErr.Contains(pattern))
|
||||
.FailWith(AppendDiagnosticsTo($"The command error output did not contain expected result: {pattern}{Environment.NewLine}"));
|
||||
return new AndConstraint<CommandResultAssertions>(this);
|
||||
}
|
||||
|
||||
public AndConstraint<CommandResultAssertions> HaveStdErrMatching(string pattern, RegexOptions options = RegexOptions.None)
|
||||
{
|
||||
Execute.Assertion.ForCondition(Regex.Match(_commandResult.StdErr, pattern, options).Success)
|
||||
.FailWith(AppendDiagnosticsTo($"Matching the command error output failed. Pattern: {pattern}{Environment.NewLine}"));
|
||||
return new AndConstraint<CommandResultAssertions>(this);
|
||||
}
|
||||
|
||||
public AndConstraint<CommandResultAssertions> NotHaveStdOut()
|
||||
{
|
||||
Execute.Assertion.ForCondition(string.IsNullOrEmpty(_commandResult.StdOut))
|
||||
|
|
|
@ -11,23 +11,25 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
public sealed class BuildCommand : TestCommand
|
||||
{
|
||||
private Project _project;
|
||||
private string _projectPath;
|
||||
private string _outputDirectory;
|
||||
private string _buidBasePathDirectory;
|
||||
private string _configuration;
|
||||
private string _framework;
|
||||
private string _versionSuffix;
|
||||
private bool _noHost;
|
||||
private bool _native;
|
||||
private string _architecture;
|
||||
private string _ilcArgs;
|
||||
private string _ilcPath;
|
||||
private string _appDepSDKPath;
|
||||
private bool _nativeCppMode;
|
||||
private string _cppCompilerFlags;
|
||||
private bool _buildProfile;
|
||||
private bool _noIncremental;
|
||||
private bool _noDependencies;
|
||||
private readonly string _projectPath;
|
||||
private readonly string _outputDirectory;
|
||||
private readonly string _buidBasePathDirectory;
|
||||
private readonly string _configuration;
|
||||
private readonly string _framework;
|
||||
private readonly string _versionSuffix;
|
||||
private readonly bool _noHost;
|
||||
private readonly bool _native;
|
||||
private readonly string _architecture;
|
||||
private readonly string _ilcArgs;
|
||||
private readonly string _ilcPath;
|
||||
private readonly string _appDepSDKPath;
|
||||
private readonly bool _nativeCppMode;
|
||||
private readonly string _cppCompilerFlags;
|
||||
private readonly bool _buildProfile;
|
||||
private readonly bool _noIncremental;
|
||||
private readonly bool _noDependencies;
|
||||
private readonly string _runtime;
|
||||
private readonly bool _forcePortable;
|
||||
|
||||
private string OutputOption
|
||||
{
|
||||
|
@ -39,6 +41,16 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
}
|
||||
}
|
||||
|
||||
private string ForcePortableOption
|
||||
{
|
||||
get
|
||||
{
|
||||
return _forcePortable ?
|
||||
"--portable" :
|
||||
string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildBasePathOption
|
||||
{
|
||||
get
|
||||
|
@ -98,6 +110,16 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
}
|
||||
}
|
||||
|
||||
private string RuntimeOption
|
||||
{
|
||||
get
|
||||
{
|
||||
return _runtime == string.Empty ?
|
||||
"" :
|
||||
$"--runtime {_runtime}";
|
||||
}
|
||||
}
|
||||
|
||||
private string ArchitectureOption
|
||||
{
|
||||
get
|
||||
|
@ -194,6 +216,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
string buidBasePath="",
|
||||
string configuration="",
|
||||
string framework="",
|
||||
string runtime="",
|
||||
string versionSuffix="",
|
||||
bool noHost=false,
|
||||
bool native=false,
|
||||
|
@ -205,7 +228,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
string cppCompilerFlags="",
|
||||
bool buildProfile=true,
|
||||
bool noIncremental=false,
|
||||
bool noDependencies=false
|
||||
bool noDependencies=false,
|
||||
bool forcePortable=false
|
||||
)
|
||||
: base("dotnet")
|
||||
{
|
||||
|
@ -217,6 +241,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
_configuration = configuration;
|
||||
_versionSuffix = versionSuffix;
|
||||
_framework = framework;
|
||||
_runtime = runtime;
|
||||
_noHost = noHost;
|
||||
_native = native;
|
||||
_architecture = architecture;
|
||||
|
@ -228,6 +253,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
_buildProfile = buildProfile;
|
||||
_noIncremental = noIncremental;
|
||||
_noDependencies = noDependencies;
|
||||
_forcePortable = forcePortable;
|
||||
}
|
||||
|
||||
public override CommandResult Execute(string args = "")
|
||||
|
@ -251,7 +277,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
|
||||
private string BuildArgs()
|
||||
{
|
||||
return $"{BuildProfile} {NoDependencies} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {VersionSuffixOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
|
||||
return $"{BuildProfile} {ForcePortableOption} {NoDependencies} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {RuntimeOption} {VersionSuffixOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
55
test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs
Normal file
55
test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System.IO;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Builder.Tests
|
||||
{
|
||||
public class BuildInvalidArgumentsTests : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void ErrorOccursWhenBuildingPortableProjectToSpecificOutputPathWithoutSpecifyingFramework()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("BuildTestPortableProject")
|
||||
.WithLockFiles();
|
||||
|
||||
var result = new BuildCommand(
|
||||
projectPath: testInstance.TestRoot,
|
||||
output: Path.Combine(testInstance.TestRoot, "out"))
|
||||
.ExecuteWithCapturedOutput();
|
||||
|
||||
result.Should().Fail();
|
||||
result.Should().HaveStdErrContaining("When the '--output' option is provided, the '--framework' option must also be provided.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ErrorOccursWhenBuildingPortableProjectAndSpecifyingFrameworkThatProjectDoesNotSupport()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("BuildTestPortableProject")
|
||||
.WithLockFiles();
|
||||
|
||||
var result = new BuildCommand(
|
||||
projectPath: testInstance.TestRoot,
|
||||
output: Path.Combine(testInstance.TestRoot, "out"),
|
||||
framework: "sl40")
|
||||
.ExecuteWithCapturedOutput();
|
||||
|
||||
result.Should().Fail();
|
||||
result.Should().HaveStdErrContaining("Project does not support framework: Silverlight,Version=v4.0.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ErrorOccursWhenBuildingStandaloneProjectToSpecificOutputPathWithoutSpecifyingFramework()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("BuildTestStandaloneProject")
|
||||
.WithLockFiles();
|
||||
|
||||
var result = new BuildCommand(
|
||||
projectPath: testInstance.TestRoot,
|
||||
output: Path.Combine(testInstance.TestRoot, "out"))
|
||||
.ExecuteWithCapturedOutput();
|
||||
|
||||
result.Should().Fail();
|
||||
result.Should().HaveStdErrContaining("When the '--output' option is provided, the '--framework' option must also be provided.");
|
||||
}
|
||||
}
|
||||
}
|
44
test/dotnet-build.Tests/BuildPortableTests.cs
Normal file
44
test/dotnet-build.Tests/BuildPortableTests.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using System.IO;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Builder.Tests
|
||||
{
|
||||
public class BuildPortableTests : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void BuildingAPortableProjectProducesDepsFile()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("BuildTestPortableProject")
|
||||
.WithLockFiles();
|
||||
|
||||
var result = new BuildCommand(
|
||||
projectPath: testInstance.TestRoot,
|
||||
forcePortable: true)
|
||||
.ExecuteWithCapturedOutput();
|
||||
|
||||
result.Should().Pass();
|
||||
|
||||
var outputBase = new DirectoryInfo(Path.Combine(testInstance.TestRoot, "bin", "Debug"));
|
||||
|
||||
var netstandardappOutput = outputBase.Sub("netstandardapp1.5");
|
||||
var fxSubdirs = new[] {
|
||||
netstandardappOutput,
|
||||
outputBase.Sub("net45")
|
||||
};
|
||||
|
||||
foreach(var fxSubdir in fxSubdirs)
|
||||
{
|
||||
fxSubdir.Should()
|
||||
.Exist().And
|
||||
.HaveFiles(new[]
|
||||
{
|
||||
"BuildTestPortableProject.dll",
|
||||
"BuildTestPortableProject.pdb"
|
||||
});
|
||||
}
|
||||
|
||||
netstandardappOutput.Should().HaveFile("BuildTestPortableProject.deps");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,7 +75,7 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
|
|||
|
||||
// second build with no dependencies and no incremental; only the root rebuilds
|
||||
var result2 = BuildProject(noDependencies: true, noIncremental: true);
|
||||
result2.Should().StdOutMatchPattern("Compiling.*L0.*");
|
||||
result2.Should().HaveStdOutMatching("Compiling.*L0.*");
|
||||
|
||||
AssertResultDoesNotContainStrings(result2, dependencies);
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ namespace Microsoft.DotNet.Tools.Publish.Tests
|
|||
var publishCommand = new PublishCommand(testProject);
|
||||
var result = publishCommand.ExecuteWithCapturedOutput();
|
||||
|
||||
result.Should().StdOutMatchPattern("\nprepublish_output( \\?[^%]+\\?){5}.+\npostpublish_output( \\?[^%]+\\?){5}", RegexOptions.Singleline);
|
||||
result.Should().HaveStdOutMatching("\nprepublish_output( \\?[^%]+\\?){5}.+\npostpublish_output( \\?[^%]+\\?){5}", RegexOptions.Singleline);
|
||||
result.Should().Pass();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue