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:
Andrew Stanton-Nurse 2016-03-01 17:42:44 -08:00
parent 444e4f9fd7
commit 7cc90d9ad1
22 changed files with 334 additions and 99 deletions

View file

@ -0,0 +1,3 @@
public static class Thingy
{
}

View file

@ -0,0 +1,16 @@
{
"dependencies": {
},
"frameworks": {
"net45": {},
"netstandardapp1.5": {
"imports": [
"dnxcore50",
"portable-net45+win8"
],
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23901"
}
}
}
}

View file

@ -0,0 +1,3 @@
public static class Thingy
{
}

View file

@ -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": {}
}
}

View file

@ -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

View file

@ -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)
{

View file

@ -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"
}
}
}

View file

@ -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()
{

View file

@ -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
{

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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();

View file

@ -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;
});

View file

@ -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);

View file

@ -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%" }
}

View file

@ -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))

View file

@ -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}";
}
}
}

View 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.");
}
}
}

View 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");
}
}
}

View file

@ -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);

View file

@ -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();
}
}