Merge pull request #727 from piotrpMSFT/piotrpMSFT/issue679/CommandResolver
Packaged Commands Fixes #697 Fixes #226 Fixes #118
This commit is contained in:
commit
6803bfd1ac
38 changed files with 815 additions and 360 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -262,3 +262,4 @@ _Pvt_Extensions
|
|||
# Exceptions
|
||||
# Build Scripts
|
||||
!scripts/build/
|
||||
test/PackagedCommands/Consumers/*/project.json
|
||||
|
|
|
@ -34,9 +34,8 @@ else {
|
|||
header "Compiling"
|
||||
_ "$RepoRoot\scripts\compile\compile.ps1" @("$Configuration")
|
||||
|
||||
# Put stage2 on the PATH now that we have a build
|
||||
$env:PATH = "$Stage2Dir\bin;$env:PATH"
|
||||
$env:DOTNET_HOME = "$Stage2Dir"
|
||||
header "Setting Stage2 as PATH and DOTNET_TOOLS"
|
||||
setPathAndHome "$Stage2Dir"
|
||||
|
||||
header "Running Tests"
|
||||
_ "$RepoRoot\scripts\test\runtests.ps1"
|
||||
|
|
|
@ -37,12 +37,11 @@ fi
|
|||
header "Compiling"
|
||||
$REPOROOT/scripts/compile/compile.sh
|
||||
|
||||
# Put stage2 on the PATH now that we have a build
|
||||
export DOTNET_TOOLS=$STAGE1_DIR
|
||||
export PATH=$STAGE2_DIR/bin:$PATH
|
||||
header "Setting Stage2 as PATH, DOTNET_HOME, and DOTNET_TOOLS"
|
||||
export DOTNET_HOME=$STAGE2_DIR && export DOTNET_TOOLS=$STAGE2DIR && export PATH=$STAGE2_DIR/bin:$PATH
|
||||
|
||||
header "Testing stage2..."
|
||||
DOTNET_HOME=$STAGE2_DIR DOTNET_TOOLS=$STAGE2_DIR $REPOROOT/scripts/test/runtests.sh
|
||||
header "Running Tests"
|
||||
$REPOROOT/scripts/test/runtests.sh
|
||||
|
||||
header "Validating Dependencies"
|
||||
$REPOROOT/scripts/test/validate-dependencies.sh
|
||||
|
|
|
@ -20,4 +20,4 @@ $PackageDir = "$RepoRoot\artifacts\packages\dnvm"
|
|||
setEnvIfDefault "DOTNET_INSTALL_DIR" "$(Convert-Path "$PSScriptRoot\..")\.dotnet_stage0\win7-x64"
|
||||
setEnvIfDefault "DOTNET_BUILD_VERSION" "0.1.0.0"
|
||||
setPathAndHomeIfDefault "$Stage2Dir"
|
||||
setEnvIfDefault "CONFIGURATION" "Debug"
|
||||
setVarIfDefault "Configuration" "Debug"
|
||||
|
|
|
@ -26,13 +26,26 @@ function setEnvIfDefault([string]$envVarName, [string]$value)
|
|||
}
|
||||
}
|
||||
|
||||
function setVarIfDefault([string]$varName, [string]$value)
|
||||
{
|
||||
If (-not (Get-Variable -name $varName -ErrorAction SilentlyContinue))
|
||||
{
|
||||
Set-Variable -name $varName -value $value -scope 1
|
||||
}
|
||||
}
|
||||
|
||||
function setPathAndHomeIfDefault([string]$rootPath)
|
||||
{
|
||||
If ($env:DOTNET_HOME -eq $null)
|
||||
{
|
||||
setPathAndHome $rootPath
|
||||
}
|
||||
}
|
||||
|
||||
function setPathAndHome([string]$rootPath)
|
||||
{
|
||||
$env:DOTNET_HOME=$rootPath
|
||||
$env:PATH="$rootPath\bin;$env:PATH"
|
||||
}
|
||||
}
|
||||
|
||||
function _([string]$command)
|
||||
|
|
|
@ -11,7 +11,4 @@ $env:PATH = "$env:DOTNET_INSTALL_DIR\cli\bin;$StartPath"
|
|||
|
||||
_ "$RepoRoot\scripts\compile\compile-stage.ps1" @("$Tfm","$Rid","$Configuration","$Stage1Dir","$RepoRoot","$HostDir")
|
||||
|
||||
# Copy dnx into stage 1
|
||||
cp -rec "$DnxRoot\" "$Stage1Dir\bin\dnx\"
|
||||
|
||||
$env:PATH=$StartPath
|
|
@ -23,11 +23,4 @@ export PATH=$DOTNET_INSTALL_DIR/bin:$PATH
|
|||
header "Building stage1 dotnet using downloaded stage0 ..."
|
||||
OUTPUT_DIR=$STAGE1_DIR $REPOROOT/scripts/compile/compile-stage.sh
|
||||
|
||||
# Copy DNX in to stage1
|
||||
cp -R $DNX_ROOT $STAGE1_DIR/bin/dnx
|
||||
|
||||
# Copy and CHMOD the dotnet-dnx script
|
||||
cp $REPOROOT/scripts/dotnet-dnx.sh $STAGE1_DIR/bin/dotnet-dnx
|
||||
chmod a+x $STAGE1_DIR/bin/dotnet-dnx
|
||||
|
||||
export PATH=$StartPath
|
69
scripts/test/package-command-test.ps1
Normal file
69
scripts/test/package-command-test.ps1
Normal file
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
. "$PSScriptRoot\..\common\_common.ps1"
|
||||
|
||||
$TestPackagesPath = "$RepoRoot\tests\packages"
|
||||
|
||||
if((Test-Path $TestPackagesPath) -eq 0)
|
||||
{
|
||||
mkdir $TestPackagesPath;
|
||||
}
|
||||
|
||||
"v1", "v2" |
|
||||
foreach {
|
||||
dotnet pack "$RepoRoot\test\PackagedCommands\Commands\dotnet-hello\$_\dotnet-hello"
|
||||
cp "$RepoRoot\test\PackagedCommands\Commands\dotnet-hello\$_\dotnet-hello\bin\Debug\*.nupkg" -Destination $TestPackagesPath
|
||||
if (!$?) {
|
||||
error "Command failed: dotnet pack"
|
||||
Exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# workaround for dotnet-restore from the root failing for these tests since their dependencies aren't built yet
|
||||
dir "$RepoRoot\test\PackagedCommands\Consumers" | where {$_.PsIsContainer} |
|
||||
foreach {
|
||||
pushd "$RepoRoot\test\PackagedCommands\Consumers\$_"
|
||||
copy project.json.template project.json
|
||||
popd
|
||||
}
|
||||
|
||||
#restore test projects
|
||||
pushd "$RepoRoot\test\PackagedCommands\Consumers"
|
||||
dotnet restore -s "$TestPackagesPath" --no-cache --ignore-failed-sources --parallel
|
||||
if (!$?) {
|
||||
error "Command failed: dotnet restore"
|
||||
Exit 1
|
||||
}
|
||||
popd
|
||||
|
||||
#compile apps
|
||||
dir "$RepoRoot\test\PackagedCommands\Consumers" | where {$_.PsIsContainer} | where {$_.Name.Contains("Direct")} |
|
||||
foreach {
|
||||
pushd "$RepoRoot\test\PackagedCommands\Consumers\$_"
|
||||
dotnet compile
|
||||
popd
|
||||
}
|
||||
|
||||
#run test
|
||||
dir "$RepoRoot\test\PackagedCommands\Consumers" | where {$_.PsIsContainer} | where {$_.Name.Contains("AppWith")} |
|
||||
foreach {
|
||||
$testName = "test\PackagedCommands\Consumers\$_"
|
||||
pushd "$RepoRoot\$testName"
|
||||
$outputArray = dotnet hello | Out-String
|
||||
$output = [string]::Join('\n', $outputArray).Trim("`r", "`n")
|
||||
|
||||
del "project.json"
|
||||
if ($output -ne "hello") {
|
||||
error "Test Failed: $testName\dotnet hello"
|
||||
error " printed $output"
|
||||
Exit 1
|
||||
}
|
||||
|
||||
info "Test passed: $testName"
|
||||
popd
|
||||
}
|
||||
|
||||
Exit 0
|
72
scripts/test/package-command-test.sh
Executable file
72
scripts/test/package-command-test.sh
Executable file
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
source "$DIR/../common/_common.sh"
|
||||
|
||||
TestPackagesPath="$REPOROOT/tests/packages"
|
||||
|
||||
mkdir "$REPOROOT/tests"
|
||||
mkdir "$TestPackagesPath"
|
||||
|
||||
dotnet pack "$REPOROOT/test/PackagedCommands/Commands/dotnet-hello/v1/dotnet-hello"
|
||||
cp "$REPOROOT/test/PackagedCommands/Commands/dotnet-hello/v1/dotnet-hello/bin/Debug/"*.nupkg "$TestPackagesPath"
|
||||
dotnet pack "$REPOROOT/test/PackagedCommands/Commands/dotnet-hello/v2/dotnet-hello"
|
||||
cp "$REPOROOT/test/PackagedCommands/Commands/dotnet-hello/v2/dotnet-hello/bin/Debug/"*.nupkg "$TestPackagesPath"
|
||||
|
||||
# enable restore for test projects
|
||||
for test in $(ls -l "$REPOROOT/test/PackagedCommands/Consumers" | grep ^d | awk '{print $9}' | grep "AppWith")
|
||||
do
|
||||
pushd "$REPOROOT/test/PackagedCommands/Consumers/$test"
|
||||
cp "project.json.template" "project.json"
|
||||
popd
|
||||
done
|
||||
|
||||
# restore test projects
|
||||
pushd "$REPOROOT/test/PackagedCommands/Consumers"
|
||||
dotnet restore -s "$TestPackagesPath" --no-cache --ignore-failed-sources --parallel
|
||||
popd
|
||||
|
||||
#compile tests with direct dependencies
|
||||
for test in $(ls -l "$REPOROOT/test/PackagedCommands/Consumers" | grep ^d | awk '{print $9}' | grep "Direct")
|
||||
do
|
||||
pushd "$REPOROOT/test/PackagedCommands/Consumers/$test"
|
||||
dotnet compile
|
||||
popd
|
||||
done
|
||||
|
||||
#run test
|
||||
for test in $(ls -l "$REPOROOT/test/PackagedCommands/Consumers" | grep ^d | awk '{print $9}' | grep "AppWith")
|
||||
do
|
||||
testName="test/PackagedCommands/Consumers/$test"
|
||||
|
||||
pushd "$REPOROOT/$testName"
|
||||
|
||||
output=$(dotnet hello)
|
||||
|
||||
rm "project.json"
|
||||
|
||||
if [ "$output" == "Hello" ] ;
|
||||
then
|
||||
echo "Test Passed: $testName"
|
||||
else
|
||||
error "Test Failed: $testName/dotnet hello"
|
||||
error " printed $output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
popd
|
||||
done
|
|
@ -59,6 +59,13 @@ $TestProjects | ForEach-Object {
|
|||
|
||||
popd
|
||||
|
||||
& $RepoRoot\scripts\test\package-command-test.ps1
|
||||
$exitCode = $LastExitCode
|
||||
if ($exitCode -ne 0) {
|
||||
$failCount += 1
|
||||
$failingTests += "package-command-test"
|
||||
}
|
||||
|
||||
if ($failCount -ne 0) {
|
||||
Write-Host -ForegroundColor Red "The following tests failed."
|
||||
$failingTests | ForEach-Object {
|
||||
|
|
|
@ -12,6 +12,7 @@ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symli
|
|||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
source "$DIR/../common/_common.sh"
|
||||
|
@ -51,6 +52,12 @@ do
|
|||
fi
|
||||
done
|
||||
|
||||
"$REPOROOT/scripts/test/package-command-test.sh"
|
||||
if [ $? -ne 0 ]; then
|
||||
failCount+=1
|
||||
failedTests+=("package-command-test.sh")
|
||||
fi
|
||||
|
||||
for test in ${failedTests[@]}
|
||||
do
|
||||
error "$test.dll failed. Logs in '$TestBinRoot/${test}-testResults.xml'"
|
||||
|
|
|
@ -5,12 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
|
@ -21,179 +16,48 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
private readonly StreamForwarder _stdOut;
|
||||
private readonly StreamForwarder _stdErr;
|
||||
|
||||
public enum CommandResolutionStrategy
|
||||
{
|
||||
//command loaded from a nuget package
|
||||
NugetPackage,
|
||||
|
||||
//command loaded from the same directory as the executing assembly
|
||||
BaseDirectory,
|
||||
|
||||
//command loaded from path
|
||||
Path,
|
||||
|
||||
//command not found
|
||||
None
|
||||
}
|
||||
|
||||
private bool _running = false;
|
||||
|
||||
private Command(string executable, string args, CommandResolutionStrategy resolutionStrategy)
|
||||
private Command(CommandSpec commandSpec)
|
||||
{
|
||||
// Set the things we need
|
||||
var psi = new ProcessStartInfo()
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = executable,
|
||||
Arguments = args,
|
||||
FileName = commandSpec.Path,
|
||||
Arguments = commandSpec.Args,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true
|
||||
};
|
||||
|
||||
_process = new Process()
|
||||
_stdOut = new StreamForwarder();
|
||||
_stdErr = new StreamForwarder();
|
||||
|
||||
_process = new Process
|
||||
{
|
||||
StartInfo = psi
|
||||
};
|
||||
|
||||
_stdOut = new StreamForwarder();
|
||||
_stdErr = new StreamForwarder();
|
||||
|
||||
ResolutionStrategy = resolutionStrategy;
|
||||
ResolutionStrategy = commandSpec.ResolutionStrategy;
|
||||
}
|
||||
|
||||
public static Command Create(string executable, IEnumerable<string> args, NuGetFramework framework = null)
|
||||
public static Command Create(string commandName, IEnumerable<string> args, NuGetFramework framework = null)
|
||||
{
|
||||
return Create(executable, string.Join(" ", args), framework);
|
||||
return Create(commandName, string.Join(" ", args), framework);
|
||||
}
|
||||
|
||||
public static Command Create(string executable, string args, NuGetFramework framework = null)
|
||||
public static Command Create(string commandName, string args, NuGetFramework framework = null)
|
||||
{
|
||||
var commandSpec = CommandResolver.TryResolveCommandSpec(commandName, args, framework);
|
||||
|
||||
var resolutionStrategy = CommandResolutionStrategy.None;
|
||||
|
||||
ResolveExecutablePath(ref executable, ref args, ref resolutionStrategy, framework);
|
||||
|
||||
return new Command(executable, args, resolutionStrategy);
|
||||
}
|
||||
|
||||
private static void ResolveExecutablePath(ref string executable, ref string args, ref CommandResolutionStrategy resolutionStrategy, NuGetFramework framework = null)
|
||||
{
|
||||
executable =
|
||||
ResolveExecutablePathFromProject(executable, framework, ref resolutionStrategy) ??
|
||||
ResolveExecutableFromPath(executable, ref args, ref resolutionStrategy);
|
||||
}
|
||||
|
||||
private static string ResolveExecutableFromPath(string executable, ref string args, ref CommandResolutionStrategy resolutionStrategy)
|
||||
{
|
||||
resolutionStrategy = CommandResolutionStrategy.Path;
|
||||
|
||||
foreach (string suffix in Constants.RunnableSuffixes)
|
||||
if (commandSpec == null)
|
||||
{
|
||||
var fullExecutable = Path.GetFullPath(Path.Combine(
|
||||
AppContext.BaseDirectory, executable + suffix));
|
||||
|
||||
if (File.Exists(fullExecutable))
|
||||
{
|
||||
executable = fullExecutable;
|
||||
|
||||
resolutionStrategy = CommandResolutionStrategy.BaseDirectory;
|
||||
|
||||
// In priority order we've found the best runnable extension, so break.
|
||||
break;
|
||||
}
|
||||
throw new CommandUnknownException(commandName);
|
||||
}
|
||||
|
||||
var command = new Command(commandSpec);
|
||||
|
||||
// On Windows, we want to avoid using "cmd" if possible (it mangles the colors, and a bunch of other things)
|
||||
// So, do a quick path search to see if we can just directly invoke it
|
||||
var useCmd = ShouldUseCmd(executable);
|
||||
|
||||
if (useCmd)
|
||||
{
|
||||
var comSpec = Environment.GetEnvironmentVariable("ComSpec");
|
||||
// wrap 'executable' within quotes to deal woth space in its path.
|
||||
args = $"/S /C \"\"{executable}\" {args}\"";
|
||||
executable = comSpec;
|
||||
}
|
||||
|
||||
return executable;
|
||||
return command;
|
||||
}
|
||||
|
||||
private static string ResolveExecutablePathFromProject(string executable, NuGetFramework framework, ref CommandResolutionStrategy resolutionStrategy)
|
||||
{
|
||||
if (framework == null) return null;
|
||||
|
||||
var projectRootPath = Directory.GetCurrentDirectory();
|
||||
|
||||
if (!File.Exists(Path.Combine(projectRootPath, Project.FileName))) return null;
|
||||
|
||||
var commandName = Path.GetFileNameWithoutExtension(executable);
|
||||
|
||||
var projectContext = ProjectContext.Create(projectRootPath, framework);
|
||||
|
||||
var commandPackage = projectContext.LibraryManager.GetLibraries()
|
||||
.Where(l => l.GetType() == typeof (PackageDescription))
|
||||
.Select(l => l as PackageDescription)
|
||||
.FirstOrDefault(p =>
|
||||
{
|
||||
var fileNames = p.Library.Files
|
||||
.Select(Path.GetFileName)
|
||||
.Where(n => Path.GetFileNameWithoutExtension(n) == commandName)
|
||||
.ToList();
|
||||
|
||||
return fileNames.Contains(commandName + FileNameSuffixes.DotNet.Exe) &&
|
||||
fileNames.Contains(commandName + FileNameSuffixes.DotNet.DynamicLib) &&
|
||||
fileNames.Contains(commandName + FileNameSuffixes.Deps);
|
||||
});
|
||||
|
||||
if (commandPackage == null) return null;
|
||||
|
||||
var commandPath = commandPackage.Library.Files
|
||||
.First(f => Path.GetFileName(f) == commandName + FileNameSuffixes.DotNet.Exe);
|
||||
|
||||
resolutionStrategy = CommandResolutionStrategy.NugetPackage;
|
||||
|
||||
return Path.Combine(projectContext.PackagesDirectory, commandPackage.Path, commandPath);
|
||||
}
|
||||
|
||||
private static bool ShouldUseCmd(string executable)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var extension = Path.GetExtension(executable);
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
return !string.Equals(extension, ".exe", StringComparison.Ordinal);
|
||||
}
|
||||
else if (executable.Contains(Path.DirectorySeparatorChar))
|
||||
{
|
||||
// It's a relative path without an extension
|
||||
if (File.Exists(executable + ".exe"))
|
||||
{
|
||||
// It refers to an exe!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search the path to see if we can find it
|
||||
foreach (var path in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator))
|
||||
{
|
||||
var candidate = Path.Combine(path, executable + ".exe");
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
// We found an exe!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It's a non-exe :(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Non-windows never uses cmd
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public CommandResult Execute()
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"Running {_process.StartInfo.FileName} {_process.StartInfo.Arguments}");
|
||||
|
@ -334,147 +198,4 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class StreamForwarder
|
||||
{
|
||||
private const int DefaultBufferSize = 256;
|
||||
|
||||
private readonly int _bufferSize;
|
||||
private StringBuilder _builder;
|
||||
private StringWriter _capture;
|
||||
private Action<string> _write;
|
||||
private Action<string> _writeLine;
|
||||
|
||||
public StreamForwarder(int bufferSize = DefaultBufferSize)
|
||||
{
|
||||
_bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void Capture()
|
||||
{
|
||||
if (_capture != null)
|
||||
{
|
||||
throw new InvalidOperationException("Already capturing stream!");
|
||||
}
|
||||
_capture = new StringWriter();
|
||||
}
|
||||
|
||||
public string GetCapturedOutput()
|
||||
{
|
||||
return _capture?.GetStringBuilder()?.ToString();
|
||||
}
|
||||
|
||||
public void ForwardTo(Action<string> write, Action<string> writeLine)
|
||||
{
|
||||
if (writeLine == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(writeLine));
|
||||
}
|
||||
if (_writeLine != null)
|
||||
{
|
||||
throw new InvalidOperationException("Already handling stream!");
|
||||
}
|
||||
_write = write;
|
||||
_writeLine = writeLine;
|
||||
}
|
||||
|
||||
public Thread BeginRead(TextReader reader)
|
||||
{
|
||||
var thread = new Thread(() => Read(reader)) { IsBackground = true };
|
||||
thread.Start();
|
||||
return thread;
|
||||
}
|
||||
|
||||
public void Read(TextReader reader)
|
||||
{
|
||||
_builder = new StringBuilder();
|
||||
var buffer = new char[_bufferSize];
|
||||
int n;
|
||||
while ((n = reader.Read(buffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
_builder.Append(buffer, 0, n);
|
||||
WriteBlocks();
|
||||
}
|
||||
WriteRemainder();
|
||||
}
|
||||
|
||||
private void WriteBlocks()
|
||||
{
|
||||
int n = _builder.Length;
|
||||
if (n == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
bool sawReturn = false;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
char c = _builder[i];
|
||||
switch (c)
|
||||
{
|
||||
case '\r':
|
||||
sawReturn = true;
|
||||
continue;
|
||||
case '\n':
|
||||
WriteLine(_builder.ToString(offset, i - offset - (sawReturn ? 1 : 0)));
|
||||
offset = i + 1;
|
||||
break;
|
||||
}
|
||||
sawReturn = false;
|
||||
}
|
||||
|
||||
// If the buffer contains no line breaks and _write is
|
||||
// supported, send the buffer content.
|
||||
if (!sawReturn &&
|
||||
(offset == 0) &&
|
||||
((_write != null) || (_writeLine == null)))
|
||||
{
|
||||
WriteRemainder();
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.Remove(0, offset);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteRemainder()
|
||||
{
|
||||
if (_builder.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Write(_builder.ToString());
|
||||
_builder.Clear();
|
||||
}
|
||||
|
||||
private void WriteLine(string str)
|
||||
{
|
||||
if (_capture != null)
|
||||
{
|
||||
_capture.WriteLine(str);
|
||||
}
|
||||
// If _write is supported, so is _writeLine.
|
||||
if (_writeLine != null)
|
||||
{
|
||||
_writeLine(str);
|
||||
}
|
||||
}
|
||||
|
||||
private void Write(string str)
|
||||
{
|
||||
if (_capture != null)
|
||||
{
|
||||
_capture.Write(str);
|
||||
}
|
||||
if (_write != null)
|
||||
{
|
||||
_write(str);
|
||||
}
|
||||
else if (_writeLine != null)
|
||||
{
|
||||
_writeLine(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
|
|
17
src/Microsoft.DotNet.Cli.Utils/CommandResolutionStrategy.cs
Normal file
17
src/Microsoft.DotNet.Cli.Utils/CommandResolutionStrategy.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
public enum CommandResolutionStrategy
|
||||
{
|
||||
//command loaded from a nuget package
|
||||
NugetPackage,
|
||||
|
||||
//command loaded from the same directory as the executing assembly
|
||||
BaseDirectory,
|
||||
|
||||
//command loaded from path
|
||||
Path,
|
||||
|
||||
//command not found
|
||||
None
|
||||
}
|
||||
}
|
196
src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs
Normal file
196
src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs
Normal file
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NuGet.Frameworks;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using NuGet.Packaging;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal static class CommandResolver
|
||||
{
|
||||
public static CommandSpec TryResolveCommandSpec(string commandName, string args, NuGetFramework framework = null)
|
||||
{
|
||||
return ResolveFromRootedCommand(commandName, args) ??
|
||||
ResolveFromProjectDependencies(commandName, args, framework) ??
|
||||
ResolveFromProjectTools(commandName, args) ??
|
||||
ResolveFromPath(commandName, args);
|
||||
}
|
||||
|
||||
private static CommandSpec ResolveFromPath(string commandName, string args)
|
||||
{
|
||||
var commandPath = Env.GetCommandPath(commandName);
|
||||
|
||||
if (commandPath == null) return null;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
|
||||
Path.GetExtension(commandPath).Equals(".cmd", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var preferredCommandPath = Env.GetCommandPath(commandName, ".exe");
|
||||
|
||||
if (preferredCommandPath != null)
|
||||
{
|
||||
commandPath = Environment.GetEnvironmentVariable("ComSpec");
|
||||
|
||||
args = $"/S /C \"\"{preferredCommandPath}\" {args}\"";
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandSpec(commandPath, args, CommandResolutionStrategy.Path);
|
||||
}
|
||||
|
||||
private static CommandSpec ResolveFromRootedCommand(string commandName, string args)
|
||||
{
|
||||
if (Path.IsPathRooted(commandName))
|
||||
{
|
||||
return new CommandSpec(commandName, args, CommandResolutionStrategy.Path);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CommandSpec ResolveFromProjectDependencies(string commandName, string args,
|
||||
NuGetFramework framework)
|
||||
{
|
||||
if (framework == null) return null;
|
||||
|
||||
var projectContext = GetProjectContext(framework);
|
||||
|
||||
if (projectContext == null) return null;
|
||||
|
||||
var commandPackage = GetCommandPackage(projectContext, commandName);
|
||||
|
||||
if (commandPackage == null) return null;
|
||||
|
||||
var depsPath = GetDepsPath(projectContext, Constants.DefaultConfiguration);
|
||||
|
||||
return ConfigureCommandFromPackage(commandName, args, commandPackage, projectContext, depsPath);
|
||||
}
|
||||
|
||||
private static ProjectContext GetProjectContext(NuGetFramework framework)
|
||||
{
|
||||
var projectRootPath = Directory.GetCurrentDirectory();
|
||||
|
||||
if (!File.Exists(Path.Combine(projectRootPath, Project.FileName)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var projectContext = ProjectContext.Create(projectRootPath, framework);
|
||||
return projectContext;
|
||||
}
|
||||
|
||||
private static PackageDescription GetCommandPackage(ProjectContext projectContext, string commandName)
|
||||
{
|
||||
return projectContext.LibraryManager.GetLibraries()
|
||||
.Where(l => l.GetType() == typeof (PackageDescription))
|
||||
.Select(l => l as PackageDescription)
|
||||
.FirstOrDefault(p => p.Library.Files
|
||||
.Select(Path.GetFileName)
|
||||
.Where(f => Path.GetFileNameWithoutExtension(f) == commandName)
|
||||
.Select(Path.GetExtension)
|
||||
.Any(e => Env.ExecutableExtensions.Contains(e) ||
|
||||
e == FileNameSuffixes.DotNet.DynamicLib));
|
||||
}
|
||||
|
||||
public static CommandSpec ResolveFromProjectTools(string commandName, string args)
|
||||
{
|
||||
var context = GetProjectContext(FrameworkConstants.CommonFrameworks.DnxCore50);
|
||||
|
||||
if (context == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var commandLibrary = context.ProjectFile.Tools
|
||||
.FirstOrDefault(l => l.Name == commandName);
|
||||
|
||||
if (commandLibrary == default(LibraryRange))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockPath = Path.Combine(context.ProjectDirectory, "artifacts", "Tools", commandName,
|
||||
"project.lock.json");
|
||||
|
||||
if (!File.Exists(lockPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var lockFile = LockFileReader.Read(lockPath);
|
||||
|
||||
var lib = lockFile.PackageLibraries.FirstOrDefault(l => l.Name == commandName);
|
||||
var packageDir = new VersionFolderPathResolver(context.PackagesDirectory)
|
||||
.GetInstallPath(lib.Name, lib.Version);
|
||||
|
||||
return Directory.Exists(packageDir)
|
||||
? ConfigureCommandFromPackage(commandName, args, lib.Files, packageDir)
|
||||
: null;
|
||||
}
|
||||
|
||||
private static CommandSpec ConfigureCommandFromPackage(string commandName, string args, string packageDir)
|
||||
{
|
||||
var commandPackage = new PackageFolderReader(packageDir);
|
||||
|
||||
var files = commandPackage.GetFiles();
|
||||
|
||||
return ConfigureCommandFromPackage(commandName, args, files, packageDir);
|
||||
}
|
||||
|
||||
private static CommandSpec ConfigureCommandFromPackage(string commandName, string args,
|
||||
PackageDescription commandPackage, ProjectContext projectContext, string depsPath = null)
|
||||
{
|
||||
var files = commandPackage.Library.Files;
|
||||
|
||||
var packageRoot = projectContext.PackagesDirectory;
|
||||
|
||||
var packagePath = commandPackage.Path;
|
||||
|
||||
var packageDir = Path.Combine(packageRoot, packagePath);
|
||||
|
||||
return ConfigureCommandFromPackage(commandName, args, files, packageDir, depsPath);
|
||||
}
|
||||
|
||||
private static CommandSpec ConfigureCommandFromPackage(string commandName, string args,
|
||||
IEnumerable<string> files, string packageDir, string depsPath = null)
|
||||
{
|
||||
var fileName = string.Empty;
|
||||
|
||||
var commandPath = files
|
||||
.FirstOrDefault(f => Env.ExecutableExtensions.Contains(Path.GetExtension(f)));
|
||||
|
||||
if (commandPath == null)
|
||||
{
|
||||
var dllPath = files
|
||||
.Where(f => Path.GetFileName(f) == commandName + FileNameSuffixes.DotNet.DynamicLib)
|
||||
.Select(f => Path.Combine(packageDir, f))
|
||||
.FirstOrDefault();
|
||||
|
||||
fileName = CoreHost.Path;
|
||||
|
||||
if (depsPath != null)
|
||||
{
|
||||
args = $"--tpaFile:\"{depsPath}\" {args}";
|
||||
}
|
||||
|
||||
args = $"\"{dllPath}\" {args}";
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = Path.Combine(packageDir, commandPath);
|
||||
}
|
||||
|
||||
return new CommandSpec(fileName, args, CommandResolutionStrategy.NugetPackage);
|
||||
}
|
||||
|
||||
private static string GetDepsPath(ProjectContext context, string buildConfiguration)
|
||||
{
|
||||
return Path.Combine(context.GetOutputDirectoryPath(buildConfiguration),
|
||||
context.ProjectFile.Name + FileNameSuffixes.Deps);
|
||||
}
|
||||
}
|
||||
}
|
18
src/Microsoft.DotNet.Cli.Utils/CommandSpec.cs
Normal file
18
src/Microsoft.DotNet.Cli.Utils/CommandSpec.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal class CommandSpec
|
||||
{
|
||||
public CommandSpec(string path, string args, CommandResolutionStrategy resolutionStrategy)
|
||||
{
|
||||
Path = path;
|
||||
Args = args;
|
||||
ResolutionStrategy = resolutionStrategy;
|
||||
}
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public string Args { get; }
|
||||
|
||||
public CommandResolutionStrategy ResolutionStrategy { get; }
|
||||
}
|
||||
}
|
19
src/Microsoft.DotNet.Cli.Utils/CommandUnknownException.cs
Normal file
19
src/Microsoft.DotNet.Cli.Utils/CommandUnknownException.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
public class CommandUnknownException : Exception
|
||||
{
|
||||
public CommandUnknownException()
|
||||
{
|
||||
}
|
||||
|
||||
public CommandUnknownException(string commandName) : base($"No executable found matching command \"{commandName}\"")
|
||||
{
|
||||
}
|
||||
|
||||
public CommandUnknownException(string commandName, Exception innerException) : base($"No executable found matching command \"{commandName}\"", innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,6 @@
|
|||
// 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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
|
@ -13,12 +9,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
{
|
||||
public static readonly string ProjectFileName = "project.json";
|
||||
public static readonly string ExeSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty;
|
||||
|
||||
// Priority order of runnable suffixes to look for and run
|
||||
public static readonly string[] RunnableSuffixes = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? new string[] { ".exe", ".cmd", ".bat" }
|
||||
: new string[] { string.Empty };
|
||||
|
||||
|
||||
public static readonly string HostExecutableName = "corehost" + ExeSuffix;
|
||||
public static readonly string DefaultConfiguration = "Debug";
|
||||
public static readonly string BinDirectoryName = "bin";
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
using System.IO;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Compiler.Common
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal static class CoreHost
|
||||
public static class CoreHost
|
||||
{
|
||||
internal static string _path;
|
||||
|
150
src/Microsoft.DotNet.Cli.Utils/StreamForwarder.cs
Normal file
150
src/Microsoft.DotNet.Cli.Utils/StreamForwarder.cs
Normal file
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
public sealed class StreamForwarder
|
||||
{
|
||||
private const int DefaultBufferSize = 256;
|
||||
|
||||
private readonly int _bufferSize;
|
||||
private StringBuilder _builder;
|
||||
private StringWriter _capture;
|
||||
private Action<string> _write;
|
||||
private Action<string> _writeLine;
|
||||
|
||||
public StreamForwarder(int bufferSize = DefaultBufferSize)
|
||||
{
|
||||
_bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void Capture()
|
||||
{
|
||||
if (_capture != null)
|
||||
{
|
||||
throw new InvalidOperationException("Already capturing stream!");
|
||||
}
|
||||
_capture = new StringWriter();
|
||||
}
|
||||
|
||||
public string GetCapturedOutput()
|
||||
{
|
||||
return _capture?.GetStringBuilder()?.ToString();
|
||||
}
|
||||
|
||||
public void ForwardTo(Action<string> write, Action<string> writeLine)
|
||||
{
|
||||
if (writeLine == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(writeLine));
|
||||
}
|
||||
if (_writeLine != null)
|
||||
{
|
||||
throw new InvalidOperationException("Already handling stream!");
|
||||
}
|
||||
_write = write;
|
||||
_writeLine = writeLine;
|
||||
}
|
||||
|
||||
public Thread BeginRead(TextReader reader)
|
||||
{
|
||||
var thread = new Thread(() => Read(reader)) { IsBackground = true };
|
||||
thread.Start();
|
||||
return thread;
|
||||
}
|
||||
|
||||
public void Read(TextReader reader)
|
||||
{
|
||||
_builder = new StringBuilder();
|
||||
var buffer = new char[_bufferSize];
|
||||
int n;
|
||||
while ((n = reader.Read(buffer, 0, _bufferSize)) > 0)
|
||||
{
|
||||
_builder.Append(buffer, 0, n);
|
||||
WriteBlocks();
|
||||
}
|
||||
WriteRemainder();
|
||||
}
|
||||
|
||||
private void WriteBlocks()
|
||||
{
|
||||
int n = _builder.Length;
|
||||
if (n == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
bool sawReturn = false;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
char c = _builder[i];
|
||||
switch (c)
|
||||
{
|
||||
case '\r':
|
||||
sawReturn = true;
|
||||
continue;
|
||||
case '\n':
|
||||
WriteLine(_builder.ToString(offset, i - offset - (sawReturn ? 1 : 0)));
|
||||
offset = i + 1;
|
||||
break;
|
||||
}
|
||||
sawReturn = false;
|
||||
}
|
||||
|
||||
// If the buffer contains no line breaks and _write is
|
||||
// supported, send the buffer content.
|
||||
if (!sawReturn &&
|
||||
(offset == 0) &&
|
||||
((_write != null) || (_writeLine == null)))
|
||||
{
|
||||
WriteRemainder();
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.Remove(0, offset);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteRemainder()
|
||||
{
|
||||
if (_builder.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Write(_builder.ToString());
|
||||
_builder.Clear();
|
||||
}
|
||||
|
||||
private void WriteLine(string str)
|
||||
{
|
||||
if (_capture != null)
|
||||
{
|
||||
_capture.WriteLine(str);
|
||||
}
|
||||
// If _write is supported, so is _writeLine.
|
||||
if (_writeLine != null)
|
||||
{
|
||||
_writeLine(str);
|
||||
}
|
||||
}
|
||||
|
||||
private void Write(string str)
|
||||
{
|
||||
if (_capture != null)
|
||||
{
|
||||
_capture.Write(str);
|
||||
}
|
||||
if (_write != null)
|
||||
{
|
||||
_write(str);
|
||||
}
|
||||
else if (_writeLine != null)
|
||||
{
|
||||
_writeLine(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,12 @@
|
|||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
"dnxcore50": { }
|
||||
},
|
||||
"scripts": {
|
||||
"postcompile": [
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.dll\"",
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.pdb\""
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,9 +44,25 @@ Common Commands:
|
|||
{
|
||||
DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
||||
try
|
||||
{
|
||||
return ProcessArgs(args);
|
||||
}
|
||||
catch (CommandUnknownException e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int ProcessArgs(string[] args)
|
||||
{
|
||||
// CommandLineApplication is a bit restrictive, so we parse things ourselves here. Individual apps should use CLA.
|
||||
|
||||
var verbose = false;
|
||||
var success = true;
|
||||
var success = true;
|
||||
var command = string.Empty;
|
||||
var lastArg = 0;
|
||||
for (; lastArg < args.Length; lastArg++)
|
||||
|
@ -77,7 +93,8 @@ Common Commands:
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
if (!success)
|
||||
{
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
|
@ -89,7 +106,7 @@ Common Commands:
|
|||
return RunHelpCommand(appArgs);
|
||||
}
|
||||
|
||||
return Command.Create("dotnet-" + command, appArgs, new NuGetFramework("DNXCore", Version.Parse("5.0")))
|
||||
return Command.Create("dotnet-" + command, appArgs, FrameworkConstants.CommonFrameworks.DnxCore50)
|
||||
.EnvironmentVariable(CommandContext.Variables.Verbose, verbose.ToString())
|
||||
.EnvironmentVariable(CommandContext.Variables.AnsiPassThru, bool.TrueString)
|
||||
.ForwardStdErr()
|
||||
|
|
|
@ -6,7 +6,7 @@ using Microsoft.DotNet.ProjectModel.Compilation;
|
|||
|
||||
namespace Microsoft.DotNet.Cli.Compiler.Common
|
||||
{
|
||||
internal static class LibraryExporterExtensions
|
||||
public static class LibraryExporterExtensions
|
||||
{
|
||||
internal static void CopyProjectDependenciesTo(this LibraryExporter exporter, string path, params ProjectDescription[] except)
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
.CopyTo(path);
|
||||
}
|
||||
|
||||
internal static void WriteDepsTo(this IEnumerable<LibraryExport> exports, string path)
|
||||
public static void WriteDepsTo(this IEnumerable<LibraryExport> exports, string path)
|
||||
{
|
||||
File.WriteAllLines(path, exports.SelectMany(GenerateLines));
|
||||
}
|
||||
|
|
|
@ -202,10 +202,5 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
appConfig.Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetDepsPath(this ProjectContext context, string buildConfiguration)
|
||||
{
|
||||
return Path.Combine(context.GetOutputDirectoryPath(buildConfiguration), context.ProjectFile.Name + ".deps");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
{
|
||||
var pathCommands = CompilerUtil.GetCommandsInvokedByCompile(project)
|
||||
.Select(commandName => Command.Create(commandName, "", project.TargetFramework))
|
||||
.Where(c => Command.CommandResolutionStrategy.Path.Equals(c.ResolutionStrategy));
|
||||
.Where(c => c.ResolutionStrategy.Equals(CommandResolutionStrategy.Path));
|
||||
|
||||
foreach (var pathCommand in pathCommands)
|
||||
{
|
||||
|
|
|
@ -6,10 +6,12 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
|
@ -350,6 +352,17 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
runtimeContext
|
||||
.MakeCompilationOutputRunnable(outputPath, args.ConfigValue);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(context.ProjectFile.TestRunner))
|
||||
{
|
||||
var projectContext =
|
||||
ProjectContext.Create(context.ProjectDirectory, context.TargetFramework,
|
||||
new[] { PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier()});
|
||||
|
||||
projectContext
|
||||
.CreateExporter(args.ConfigValue)
|
||||
.GetDependencies(LibraryType.Package)
|
||||
.WriteDepsTo(Path.Combine(outputPath, projectContext.ProjectFile.Name + FileNameSuffixes.Deps));
|
||||
}
|
||||
|
||||
return PrintSummary(diagnostics, sw, success);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Microsoft.DotNet.Tools.Restore
|
|||
{
|
||||
var project = ProjectReader.GetProject(restoreTask.ProjectPath);
|
||||
|
||||
RestoreTools(project, restoreTask.Arguments);
|
||||
RestoreTools(project, restoreTask);
|
||||
}
|
||||
|
||||
return projectRestoreResult;
|
||||
|
@ -60,7 +60,6 @@ namespace Microsoft.DotNet.Tools.Restore
|
|||
|
||||
return -2;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return app.Execute(args);
|
||||
|
@ -101,33 +100,39 @@ namespace Microsoft.DotNet.Tools.Restore
|
|||
return firstArg.EndsWith(Project.FileName) && File.Exists(firstArg);
|
||||
}
|
||||
|
||||
private static void RestoreTools(Project project, IEnumerable<string> args)
|
||||
private static void RestoreTools(Project project, RestoreTask restoreTask)
|
||||
{
|
||||
foreach (var tooldep in project.Tools)
|
||||
{
|
||||
RestoreTool(tooldep, args);
|
||||
RestoreTool(tooldep, restoreTask);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RestoreTool(LibraryRange tooldep, IEnumerable<string> args)
|
||||
private static void RestoreTool(LibraryRange tooldep, RestoreTask restoreTask)
|
||||
{
|
||||
var tempPath = Path.Combine(Directory.GetCurrentDirectory(), Guid.NewGuid().ToString(), "bin");
|
||||
var tempPath = Path.Combine(restoreTask.ProjectDirectory, Guid.NewGuid().ToString(), "bin");
|
||||
|
||||
RestoreToolToPath(tooldep, args, tempPath);
|
||||
RestoreToolToPath(tooldep, restoreTask.Arguments, tempPath);
|
||||
|
||||
CreateDepsInPackageCache(tooldep, tempPath);
|
||||
|
||||
PersistLockFile(tooldep, tempPath);
|
||||
PersistLockFile(tooldep, tempPath, restoreTask.ProjectDirectory);
|
||||
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
|
||||
private static void PersistLockFile(LibraryRange tooldep, string tempPath)
|
||||
private static void PersistLockFile(LibraryRange tooldep, string tempPath, string projectPath)
|
||||
{
|
||||
var targetPath = Path.Combine(Directory.GetCurrentDirectory(), "artifacts", "Tools", tooldep.Name);
|
||||
if (Directory.Exists(targetPath)) Directory.Delete(targetPath, true);
|
||||
Directory.CreateDirectory(targetPath);
|
||||
File.Move(Path.Combine(tempPath, "project.lock.json"), Path.Combine(targetPath, "project.lock.json"));
|
||||
var sourcePath = Path.Combine(tempPath, "project.lock.json");
|
||||
var targetDir = Path.Combine(projectPath, "artifacts", "Tools", tooldep.Name);
|
||||
var targetPath = Path.Combine(targetDir, "project.lock.json");
|
||||
|
||||
if (Directory.Exists(targetDir)) Directory.Delete(targetDir, true);
|
||||
Directory.CreateDirectory(targetDir);
|
||||
|
||||
Console.WriteLine($"Writing '{sourcePath}' to '{targetPath}'");
|
||||
|
||||
File.Move(sourcePath, targetPath);
|
||||
}
|
||||
|
||||
private static void CreateDepsInPackageCache(LibraryRange toolLibrary, string projectPath)
|
||||
|
@ -156,6 +161,9 @@ namespace Microsoft.DotNet.Tools.Restore
|
|||
{
|
||||
Directory.CreateDirectory(tempPath);
|
||||
var projectPath = Path.Combine(tempPath, Project.FileName);
|
||||
|
||||
Console.WriteLine($"Restoring Tool '{tooldep.Name}' for '{projectPath}' in '{tempPath}'");
|
||||
|
||||
File.WriteAllText(projectPath, GenerateProjectJsonContents(new[] {"dnxcore50"}));
|
||||
Dnx.RunPackageInstall(tooldep, projectPath, args);
|
||||
Dnx.RunRestore(new [] { $"\"{projectPath}\"", "--runtime", $"{DefaultRid}"}.Concat(args));
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Restore
|
||||
{
|
||||
|
@ -6,6 +9,10 @@ namespace Microsoft.DotNet.Tools.Restore
|
|||
{
|
||||
public string ProjectPath { get; set; }
|
||||
|
||||
public IEnumerable<string> Arguments { get; set; }
|
||||
public IEnumerable<string> Arguments { get; set; }
|
||||
|
||||
public string ProjectDirectory => ProjectPath.EndsWith(Project.FileName, StringComparison.OrdinalIgnoreCase)
|
||||
? Path.GetDirectoryName(ProjectPath)
|
||||
: ProjectPath;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"dotnet-hello": { "version": "1.0.0", "target": "package" }
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
},
|
||||
|
||||
"testRunner": "must-be-specified-to-generate-deps",
|
||||
|
||||
"tools": {
|
||||
"dotnet-hello": { "version": "2.0.0", "target": "package" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"testRunner": "must-be-specified-to-generate-deps",
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"dotnet-hello": {"version": "1.0.0", "target": "package"}
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
},
|
||||
|
||||
"tools": {
|
||||
"dotnet-hello": { "version": "1.0.0", "target": "package" }
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue