diff --git a/TestAssets/TestProjects/BuildTestPortableProject/Lib.cs b/TestAssets/TestProjects/BuildTestPortableProject/Lib.cs
new file mode 100644
index 000000000..2ac94ca9d
--- /dev/null
+++ b/TestAssets/TestProjects/BuildTestPortableProject/Lib.cs
@@ -0,0 +1,3 @@
+public static class Thingy
+{
+}
diff --git a/TestAssets/TestProjects/BuildTestPortableProject/project.json b/TestAssets/TestProjects/BuildTestPortableProject/project.json
new file mode 100644
index 000000000..43c20c90b
--- /dev/null
+++ b/TestAssets/TestProjects/BuildTestPortableProject/project.json
@@ -0,0 +1,16 @@
+{
+ "dependencies": {
+ },
+ "frameworks": {
+ "net45": {},
+ "netstandardapp1.5": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+win8"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.0.0-rc2-23901"
+ }
+ }
+ }
+}
diff --git a/TestAssets/TestProjects/BuildTestStandaloneProject/Lib.cs b/TestAssets/TestProjects/BuildTestStandaloneProject/Lib.cs
new file mode 100644
index 000000000..2ac94ca9d
--- /dev/null
+++ b/TestAssets/TestProjects/BuildTestStandaloneProject/Lib.cs
@@ -0,0 +1,3 @@
+public static class Thingy
+{
+}
diff --git a/TestAssets/TestProjects/BuildTestStandaloneProject/project.json b/TestAssets/TestProjects/BuildTestStandaloneProject/project.json
new file mode 100644
index 000000000..d8b5d9d86
--- /dev/null
+++ b/TestAssets/TestProjects/BuildTestStandaloneProject/project.json
@@ -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": {}
+ }
+}
diff --git a/scripts/dev-dotnet.ps1 b/scripts/dev-dotnet.ps1
index 8b5f1290f..4728a8b7c 100644
--- a/scripts/dev-dotnet.ps1
+++ b/scripts/dev-dotnet.ps1
@@ -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
diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs
index b84fa6452..bbf03cf4f 100644
--- a/scripts/dotnet-cli-build/CompileTargets.cs
+++ b/scripts/dotnet-cli-build/CompileTargets.cs
@@ -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)
{
diff --git a/src/Microsoft.DotNet.Cli.Utils/project.json b/src/Microsoft.DotNet.Cli.Utils/project.json
index 877df020f..625b48bf4 100644
--- a/src/Microsoft.DotNet.Cli.Utils/project.json
+++ b/src/Microsoft.DotNet.Cli.Utils/project.json
@@ -19,8 +19,9 @@
"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"
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Microsoft.DotNet.Compiler.Common/Executable.cs b/src/Microsoft.DotNet.Compiler.Common/Executable.cs
index 31f92825f..3aedeedc8 100644
--- a/src/Microsoft.DotNet.Compiler.Common/Executable.cs
+++ b/src/Microsoft.DotNet.Compiler.Common/Executable.cs
@@ -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,8 +67,11 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
{
WriteDepsFileAndCopyProjectDependencies(_exporter);
- // TODO: Pick a host based on the RID
- CoreHost.CopyTo(_runtimeOutputPath, _context.ProjectFile.Name + Constants.ExeSuffix);
+ if (!string.IsNullOrEmpty(_context.RuntimeIdentifier))
+ {
+ // TODO: Pick a host based on the RID
+ CoreHost.CopyTo(_runtimeOutputPath, _context.ProjectFile.Name + Constants.ExeSuffix);
+ }
}
private void CopyContentFiles()
diff --git a/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs b/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs
index aa9c9fb87..fdaa7c5e3 100644
--- a/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs
+++ b/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs
@@ -48,12 +48,18 @@ namespace Microsoft.DotNet.ProjectModel
{
if (!string.IsNullOrEmpty(runtimeIdentifier))
{
- runtimeOutputPath= PathUtility.EnsureTrailingSlash(Path.Combine(compilationOutputPath, runtimeIdentifier));
+ 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
{
- runtimeOutputPath= PathUtility.EnsureTrailingSlash(Path.GetFullPath(outputPath));
+ runtimeOutputPath = PathUtility.EnsureTrailingSlash(Path.GetFullPath(outputPath));
}
var intermediateOutputPath = PathUtility.EnsureTrailingSlash(Path.Combine(
diff --git a/src/Microsoft.DotNet.ProjectModel/Project.cs b/src/Microsoft.DotNet.ProjectModel/Project.cs
index c4a8c4a41..5e187f55b 100644
--- a/src/Microsoft.DotNet.ProjectModel/Project.cs
+++ b/src/Microsoft.DotNet.ProjectModel/Project.cs
@@ -35,7 +35,7 @@ namespace Microsoft.DotNet.ProjectModel
return Path.GetDirectoryName(ProjectFilePath);
}
}
-
+
public AnalyzerOptions AnalyzerOptions { get; set; }
public string Name { get; set; }
@@ -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;
diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs
index 9e237ff11..99f869f36 100644
--- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs
+++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs
@@ -83,7 +83,7 @@ namespace Microsoft.DotNet.ProjectModel
.WithRuntimeIdentifiers(runtimeIdentifiers)
.Build();
}
-
+
public static ProjectContextBuilder CreateBuilder(string projectPath, NuGetFramework framework)
{
if (projectPath.EndsWith(Project.FileName))
@@ -120,15 +120,12 @@ namespace Microsoft.DotNet.ProjectModel
///
/// Creates a project context for each target located in the project at
///
- public static IEnumerable CreateContextForEachTarget(string projectPath)
+ public static IEnumerable 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 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());
+ 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;
}
diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
index 2a58b3bd5..39f28ba12 100644
--- a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
+++ b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
@@ -61,18 +61,20 @@ namespace Microsoft.DotNet.ProjectModel
return true;
}
- public static Project GetProject(string projectFile, ProjectReaderSettings settings = null)
- {
- return GetProject(projectFile, new List(), settings);
- }
+ public static Project GetProject(string projectPath, ProjectReaderSettings settings = null) => GetProject(projectPath, new List(), settings);
- public static Project GetProject(string projectFile, ICollection diagnostics, ProjectReaderSettings settings = null)
+ public static Project GetProject(string projectPath, ICollection diagnostics, ProjectReaderSettings settings = null)
{
- var name = Path.GetFileName(Path.GetDirectoryName(projectFile));
-
- using (var stream = new FileStream(projectFile, FileMode.Open, FileAccess.Read, FileShare.Read))
+ if (!projectPath.EndsWith(Project.FileName))
{
- return new ProjectReader().ReadProject(stream, name, projectFile, diagnostics, settings);
+ projectPath = Path.Combine(projectPath, Project.FileName);
+ }
+
+ var name = Path.GetFileName(Path.GetDirectoryName(projectPath));
+
+ using (var stream = new FileStream(projectPath, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ 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);
diff --git a/src/dotnet/commands/dotnet-build/CompileContext.cs b/src/dotnet/commands/dotnet-build/CompileContext.cs
index 7e0e43957..de2b43475 100644
--- a/src/dotnet/commands/dotnet-build/CompileContext.cs
+++ b/src/dotnet/commands/dotnet-build/CompileContext.cs
@@ -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)
{
@@ -395,15 +395,7 @@ namespace Microsoft.DotNet.Tools.Build
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);
- }
+ MakeRunnable();
}
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);
- CopyCompilationOutput(outputPaths);
+
+ // 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();
diff --git a/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs b/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs
index 2c7fa2a0f..9a66f1777 100644
--- a/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs
+++ b/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs
@@ -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 baseClassOptions;
@@ -77,12 +80,15 @@ namespace Microsoft.DotNet.Tools.Compiler
_outputOption = _app.Option("-o|--output ", "Directory in which to place outputs", CommandOptionType.SingleValue);
_buildBasePath = _app.Option("-b|--build-base-path ", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
- _frameworkOption = _app.Option("-f|--framework ", "Compile a specific framework", CommandOptionType.MultipleValue);
+ _frameworkOption = _app.Option("-f|--framework ", "Compile a specific framework", CommandOptionType.SingleValue);
+ _runtimeOption = _app.Option("-r|--runtime ", "Produce runtime-specific assets for the specified runtime", CommandOptionType.SingleValue);
_configurationOption = _app.Option("-c|--configuration ", "Configuration under which to build", CommandOptionType.SingleValue);
- _runtimeOption = _app.Option("-r|--runtime ", "Target runtime to publish for", CommandOptionType.SingleValue);
_versionSuffixOption = _app.Option("--version-suffix ", "Defines what `*` should be replaced with in version field in project.json", CommandOptionType.SingleValue);
_projectArgument = _app.Argument("", "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 ", "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 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;
});
diff --git a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs
index aeb692979..d2b149b31 100644
--- a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs
+++ b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs
@@ -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);
diff --git a/test/ArgumentForwardingTests/project.json b/test/ArgumentForwardingTests/project.json
index 7175750b5..8b99a663f 100644
--- a/test/ArgumentForwardingTests/project.json
+++ b/test/ArgumentForwardingTests/project.json
@@ -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%" }
}
diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs
index 00516044b..3fab175b5 100644
--- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs
+++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs
@@ -60,7 +60,14 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
return new AndConstraint(this);
}
- public AndConstraint StdOutMatchPattern(string pattern, RegexOptions options = RegexOptions.None)
+ public AndConstraint 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(this);
+ }
+
+ public AndConstraint 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(this);
}
+ public AndConstraint 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(this);
+ }
+
+ public AndConstraint 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(this);
+ }
+
public AndConstraint NotHaveStdOut()
{
Execute.Assertion.ForCondition(string.IsNullOrEmpty(_commandResult.StdOut))
diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs
index 93102cf12..da059a1fe 100644
--- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs
+++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs
@@ -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
@@ -67,7 +79,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
$"--framework {_framework}";
}
}
-
+
private string VersionSuffixOption
{
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}";
}
}
}
diff --git a/test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs b/test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs
new file mode 100644
index 000000000..15a38b24b
--- /dev/null
+++ b/test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs
@@ -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.");
+ }
+ }
+}
diff --git a/test/dotnet-build.Tests/BuildPortableTests.cs b/test/dotnet-build.Tests/BuildPortableTests.cs
new file mode 100644
index 000000000..6ecfad1f1
--- /dev/null
+++ b/test/dotnet-build.Tests/BuildPortableTests.cs
@@ -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");
+ }
+ }
+}
diff --git a/test/dotnet-build.Tests/BuildProjectToProjectTests.cs b/test/dotnet-build.Tests/BuildProjectToProjectTests.cs
index c3b55a740..8735a84a6 100644
--- a/test/dotnet-build.Tests/BuildProjectToProjectTests.cs
+++ b/test/dotnet-build.Tests/BuildProjectToProjectTests.cs
@@ -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);
diff --git a/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs b/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs
index c1dcfeda3..22562e818 100644
--- a/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs
+++ b/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs
@@ -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();
}
}