2016-10-28 01:46:43 +00:00
|
|
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
2015-12-15 01:39:29 +00:00
|
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
|
|
|
|
using Microsoft.DotNet.Cli.Utils;
|
|
|
|
using System;
|
2016-01-22 22:05:02 +00:00
|
|
|
using System.Diagnostics;
|
2016-01-22 08:42:33 +00:00
|
|
|
using System.IO;
|
2016-02-18 09:09:23 +00:00
|
|
|
using System.Collections.Generic;
|
2016-04-05 00:51:36 +00:00
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using System.Threading.Tasks;
|
2015-12-15 01:39:29 +00:00
|
|
|
|
|
|
|
namespace Microsoft.DotNet.Tools.Test.Utilities
|
|
|
|
{
|
|
|
|
public class TestCommand
|
|
|
|
{
|
|
|
|
protected string _command;
|
2016-04-27 20:43:12 +00:00
|
|
|
|
2016-04-21 20:41:22 +00:00
|
|
|
private string _baseDirectory;
|
2016-02-18 09:09:23 +00:00
|
|
|
|
2016-03-28 10:18:13 +00:00
|
|
|
public string WorkingDirectory { get; set; }
|
|
|
|
|
2016-04-05 00:51:36 +00:00
|
|
|
public Process CurrentProcess { get; set; }
|
|
|
|
|
2016-02-18 09:09:23 +00:00
|
|
|
public Dictionary<string, string> Environment { get; } = new Dictionary<string, string>();
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
private List<Action<string>> _writeLines = new List<Action<string>>();
|
|
|
|
|
2015-12-15 01:39:29 +00:00
|
|
|
public TestCommand(string command)
|
|
|
|
{
|
|
|
|
_command = command;
|
2016-04-21 20:41:22 +00:00
|
|
|
#if NET451
|
|
|
|
_baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
|
|
|
#else
|
|
|
|
_baseDirectory = AppContext.BaseDirectory;
|
|
|
|
#endif
|
2015-12-15 01:39:29 +00:00
|
|
|
}
|
|
|
|
|
2016-01-08 19:03:14 +00:00
|
|
|
public virtual CommandResult Execute(string args = "")
|
2015-12-15 01:39:29 +00:00
|
|
|
{
|
2016-01-22 08:42:33 +00:00
|
|
|
var commandPath = _command;
|
2016-03-15 18:50:14 +00:00
|
|
|
ResolveCommand(ref commandPath, ref args);
|
2015-12-15 01:39:29 +00:00
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
Console.WriteLine($"Executing - {commandPath} {args} - {WorkingDirectoryInfo()}");
|
2016-01-22 22:05:02 +00:00
|
|
|
|
|
|
|
var stdOut = new StreamForwarder();
|
|
|
|
var stdErr = new StreamForwarder();
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
AddWriteLine(Reporter.Output.WriteLine);
|
|
|
|
|
|
|
|
stdOut.ForwardTo(writeLine: WriteLine);
|
|
|
|
stdErr.ForwardTo(writeLine: WriteLine);
|
2016-01-22 22:05:02 +00:00
|
|
|
|
|
|
|
return RunProcess(commandPath, args, stdOut, stdErr);
|
2015-12-15 01:39:29 +00:00
|
|
|
}
|
2015-12-31 01:02:59 +00:00
|
|
|
|
2016-04-05 00:51:36 +00:00
|
|
|
public virtual Task<CommandResult> ExecuteAsync(string args = "")
|
|
|
|
{
|
|
|
|
var commandPath = _command;
|
|
|
|
ResolveCommand(ref commandPath, ref args);
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
Console.WriteLine($"Executing - {commandPath} {args} - {WorkingDirectoryInfo()}");
|
2016-04-05 00:51:36 +00:00
|
|
|
|
|
|
|
var stdOut = new StreamForwarder();
|
|
|
|
var stdErr = new StreamForwarder();
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
AddWriteLine(Reporter.Output.WriteLine);
|
|
|
|
|
|
|
|
stdOut.ForwardTo(writeLine: WriteLine);
|
|
|
|
stdErr.ForwardTo(writeLine: WriteLine);
|
2016-04-05 00:51:36 +00:00
|
|
|
|
|
|
|
return RunProcessAsync(commandPath, args, stdOut, stdErr);
|
|
|
|
}
|
|
|
|
|
2016-01-08 19:03:14 +00:00
|
|
|
public virtual CommandResult ExecuteWithCapturedOutput(string args = "")
|
2015-12-31 01:02:59 +00:00
|
|
|
{
|
2016-03-15 18:50:14 +00:00
|
|
|
var command = _command;
|
|
|
|
ResolveCommand(ref command, ref args);
|
|
|
|
var commandPath = Env.GetCommandPath(command, ".exe", ".cmd", "") ??
|
2016-04-21 20:41:22 +00:00
|
|
|
Env.GetCommandPathFromRootPath(_baseDirectory, command, ".exe", ".cmd", "");
|
2016-04-05 00:51:36 +00:00
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
Console.WriteLine($"Executing (Captured Output) - {commandPath} {args} - {WorkingDirectoryInfo()}");
|
2016-03-15 18:50:14 +00:00
|
|
|
|
2016-01-22 22:05:02 +00:00
|
|
|
var stdOut = new StreamForwarder();
|
|
|
|
var stdErr = new StreamForwarder();
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
stdOut.ForwardTo(writeLine: WriteLine);
|
|
|
|
stdErr.ForwardTo(writeLine: WriteLine);
|
|
|
|
|
2016-01-22 22:05:02 +00:00
|
|
|
stdOut.Capture();
|
|
|
|
stdErr.Capture();
|
|
|
|
|
|
|
|
return RunProcess(commandPath, args, stdOut, stdErr);
|
|
|
|
}
|
2016-04-05 00:51:36 +00:00
|
|
|
|
|
|
|
public void KillTree()
|
|
|
|
{
|
|
|
|
if (CurrentProcess == null)
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException("No process is available to be killed");
|
|
|
|
}
|
|
|
|
|
|
|
|
CurrentProcess.KillTree();
|
|
|
|
}
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
public void AddWriteLine(Action<string> writeLine)
|
|
|
|
{
|
|
|
|
_writeLines.Add(writeLine);
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:50:14 +00:00
|
|
|
private void ResolveCommand(ref string executable, ref string args)
|
|
|
|
{
|
|
|
|
if (executable.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
|
|
|
{
|
|
|
|
var newArgs = ArgumentEscaper.EscapeSingleArg(executable);
|
|
|
|
if (!string.IsNullOrEmpty(args))
|
|
|
|
{
|
|
|
|
newArgs += " " + args;
|
|
|
|
}
|
|
|
|
args = newArgs;
|
2016-03-15 23:41:18 +00:00
|
|
|
executable = "dotnet";
|
2016-03-15 18:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Path.IsPathRooted(executable))
|
|
|
|
{
|
|
|
|
executable = Env.GetCommandPath(executable) ??
|
2016-04-21 20:41:22 +00:00
|
|
|
Env.GetCommandPathFromRootPath(_baseDirectory, executable);
|
2016-03-15 18:50:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-22 22:05:02 +00:00
|
|
|
private CommandResult RunProcess(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
|
2016-04-05 00:51:36 +00:00
|
|
|
{
|
|
|
|
CurrentProcess = StartProcess(executable, args);
|
2016-04-22 22:01:56 +00:00
|
|
|
var taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
|
|
|
var taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
2016-04-05 00:51:36 +00:00
|
|
|
|
|
|
|
CurrentProcess.WaitForExit();
|
2016-04-22 22:01:56 +00:00
|
|
|
Task.WaitAll(taskOut, taskErr);
|
2016-04-05 00:51:36 +00:00
|
|
|
|
|
|
|
var result = new CommandResult(
|
|
|
|
CurrentProcess.StartInfo,
|
|
|
|
CurrentProcess.ExitCode,
|
|
|
|
stdOut.CapturedOutput,
|
|
|
|
stdErr.CapturedOutput);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Task<CommandResult> RunProcessAsync(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
|
|
|
|
{
|
|
|
|
CurrentProcess = StartProcess(executable, args);
|
2016-04-22 22:01:56 +00:00
|
|
|
var taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
|
|
|
var taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
2016-04-05 00:51:36 +00:00
|
|
|
|
|
|
|
var tcs = new TaskCompletionSource<CommandResult>();
|
|
|
|
CurrentProcess.Exited += (sender, arg) =>
|
|
|
|
{
|
2016-04-22 22:01:56 +00:00
|
|
|
Task.WaitAll(taskOut, taskErr);
|
2016-04-05 00:51:36 +00:00
|
|
|
var result = new CommandResult(
|
|
|
|
CurrentProcess.StartInfo,
|
|
|
|
CurrentProcess.ExitCode,
|
|
|
|
stdOut.CapturedOutput,
|
|
|
|
stdErr.CapturedOutput);
|
|
|
|
tcs.SetResult(result);
|
|
|
|
};
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Process StartProcess(string executable, string args)
|
2016-01-22 22:05:02 +00:00
|
|
|
{
|
|
|
|
var psi = new ProcessStartInfo
|
|
|
|
{
|
|
|
|
FileName = executable,
|
|
|
|
Arguments = args,
|
|
|
|
RedirectStandardError = true,
|
2016-04-05 00:51:36 +00:00
|
|
|
RedirectStandardOutput = true,
|
2016-04-21 20:41:22 +00:00
|
|
|
RedirectStandardInput = true,
|
|
|
|
UseShellExecute = false
|
2016-01-22 22:05:02 +00:00
|
|
|
};
|
|
|
|
|
2016-02-18 09:09:23 +00:00
|
|
|
foreach (var item in Environment)
|
|
|
|
{
|
2016-04-21 20:41:22 +00:00
|
|
|
#if NET451
|
|
|
|
psi.EnvironmentVariables[item.Key] = item.Value;
|
|
|
|
#else
|
2016-02-18 09:09:23 +00:00
|
|
|
psi.Environment[item.Key] = item.Value;
|
2016-04-21 20:41:22 +00:00
|
|
|
#endif
|
2016-02-18 09:09:23 +00:00
|
|
|
}
|
|
|
|
|
2016-03-28 10:18:13 +00:00
|
|
|
if (!string.IsNullOrWhiteSpace(WorkingDirectory))
|
|
|
|
{
|
|
|
|
psi.WorkingDirectory = WorkingDirectory;
|
|
|
|
}
|
|
|
|
|
2016-01-22 22:05:02 +00:00
|
|
|
var process = new Process
|
|
|
|
{
|
2016-03-28 10:18:13 +00:00
|
|
|
StartInfo = psi
|
2016-01-22 22:05:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
process.EnableRaisingEvents = true;
|
|
|
|
process.Start();
|
2016-04-05 00:51:36 +00:00
|
|
|
return process;
|
2015-12-31 01:02:59 +00:00
|
|
|
}
|
2016-10-28 01:46:43 +00:00
|
|
|
|
|
|
|
private void WriteLine(string line)
|
2016-04-22 19:17:36 +00:00
|
|
|
{
|
2016-10-28 01:46:43 +00:00
|
|
|
foreach (var writeLine in _writeLines)
|
|
|
|
{
|
|
|
|
writeLine(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private string WorkingDirectoryInfo()
|
|
|
|
{
|
|
|
|
if (WorkingDirectory == null)
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
return $" in pwd {WorkingDirectory}";
|
2016-04-22 19:17:36 +00:00
|
|
|
}
|
2015-12-15 01:39:29 +00:00
|
|
|
}
|
2016-10-28 01:46:43 +00:00
|
|
|
}
|