169 lines
6.7 KiB
C#
169 lines
6.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using ln.logging;
|
|
|
|
namespace ln.build.commands
|
|
{
|
|
public enum CRThrow { NEVER, NEGATIVE, NONZERO }
|
|
public class CommandRunner
|
|
{
|
|
public static CRThrow DefaultThrow { get; set; } = CRThrow.NONZERO;
|
|
|
|
public CRThrow Throw { get; set; } = DefaultThrow;
|
|
public string Executable { get; }
|
|
|
|
List<Argument> arguments = new List<Argument>();
|
|
public IEnumerable<Argument> Arguments => arguments;
|
|
|
|
public Logger Logger { get; }
|
|
|
|
Func<int,bool> TestExitCode = null;
|
|
|
|
public CommandRunner(string executable,params Argument[] arguments) : this(Logger.Default, executable, arguments){}
|
|
public CommandRunner(Logger logger, string executable,params Argument[] arguments) : this(logger, null, executable, arguments){}
|
|
public CommandRunner(Logger logger, Func<int,bool> testExitCode, string executable,params Argument[] args)
|
|
{
|
|
Logger = logger;
|
|
Executable = executable;
|
|
arguments.AddRange(args);
|
|
|
|
TestExitCode = testExitCode;
|
|
}
|
|
|
|
public void AddArgument(Argument argument) => arguments.Add(argument);
|
|
public void AddArguments(params Argument[] args) => arguments.AddRange(args);
|
|
|
|
public string FindFileInPath(CommandEnvironment environment, string filename)
|
|
{
|
|
Logger.Log(LogLevel.DEBUG, "Looking up {0} in paths {1}", filename, environment.Get("PATH",""));
|
|
|
|
foreach (string path in environment.Get("PATH","").Split(Path.PathSeparator))
|
|
{
|
|
string fullpath = Path.Combine(path,filename);
|
|
if (File.Exists(fullpath))
|
|
return fullpath;
|
|
}
|
|
|
|
return filename;
|
|
}
|
|
|
|
IEnumerable<string> GetArguments(CommandEnvironment environment, bool mask) => Arguments.SelectMany((e)=>e.GetArguments(environment, mask));
|
|
|
|
|
|
public int Run() => Run(new CommandEnvironment(), null, null);
|
|
public int Run(CommandEnvironment environment) => Run(environment, null, null);
|
|
public int Run(CommandEnvironment environment, Stream stdout) => Run(environment, stdout, stdout);
|
|
public int Run(Stream stdout, Stream stderr) => Run(new CommandEnvironment(), stdout, stderr);
|
|
public int Run(CommandEnvironment environment, Stream stdout, Stream stderr)
|
|
{
|
|
ProcessStartInfo psi = new ProcessStartInfo(FindFileInPath(environment, Executable), string.Join(' ', GetArguments(environment, false)))
|
|
{
|
|
CreateNoWindow = true,
|
|
RedirectStandardError = true,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardInput = true,
|
|
WorkingDirectory = environment.WorkingDirectory
|
|
};
|
|
|
|
psi.Environment.Clear();
|
|
foreach (KeyValuePair<string,string> ev in environment)
|
|
psi.Environment.Add(ev.Key,ev.Value);
|
|
|
|
environment.Logger.Log(LogLevel.INFO, "Executing: {0} {1}", psi.FileName, string.Join(' ', GetArguments(environment, true)));
|
|
|
|
Process process = Process.Start(psi);
|
|
process.WaitForExit();
|
|
|
|
if (stdout != null)
|
|
process.StandardOutput.BaseStream.CopyTo(stdout);
|
|
if (stderr != null)
|
|
process.StandardError.BaseStream.CopyTo(stderr);
|
|
|
|
environment.Logger.Log(LogLevel.INFO, "Result: {0}", process.ExitCode);
|
|
|
|
if (
|
|
((TestExitCode != null) && !TestExitCode(process.ExitCode)) ||
|
|
((Throw == CRThrow.NEGATIVE) && (process.ExitCode < 0)) ||
|
|
((Throw == CRThrow.NONZERO) && (process.ExitCode != 0))
|
|
)
|
|
throw new Exception(String.Format("{0} execution gave result {1}", psi.FileName, process.ExitCode));
|
|
|
|
return process.ExitCode;
|
|
}
|
|
|
|
public int Run(out string stdout,out string stderr) => Run(new CommandEnvironment(), out stdout, out stderr);
|
|
public int Run(CommandEnvironment environment, out string stdout,out string stderr)
|
|
{
|
|
MemoryStream outstream,errstream;
|
|
|
|
outstream = new MemoryStream();
|
|
errstream = new MemoryStream();
|
|
|
|
int status = Run(environment, outstream, errstream);
|
|
|
|
using (StreamReader sr = new StreamReader(outstream))
|
|
stdout = sr.ReadToEnd();
|
|
|
|
using (StreamReader sr = new StreamReader(errstream))
|
|
stderr = sr.ReadToEnd();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
public class Argument
|
|
{
|
|
string value;
|
|
public bool MaskValue { get; set; }
|
|
|
|
protected Argument(){ }
|
|
public Argument(string argument) : this(argument, false) { }
|
|
public Argument(string argument, bool maskValue)
|
|
{
|
|
value = argument;
|
|
MaskValue = maskValue;
|
|
}
|
|
|
|
public void SetValue(string argValue) => value = argValue;
|
|
|
|
public virtual string[] GetArguments(CommandEnvironment environment, bool mask) => (value != null) ? new string[]{ (mask && MaskValue) ? "*****" : value } : new string[0];
|
|
|
|
public static implicit operator Argument(String s) => new Argument(s);
|
|
}
|
|
|
|
public class Option : Argument
|
|
{
|
|
public string OptionArgument { get; }
|
|
public Func<CommandEnvironment,string> GetValue { get; }
|
|
|
|
public Option(string optionArgument, string optionValue) : this(optionArgument, optionValue, false){ }
|
|
public Option(string optionArgument, string optionValue, bool maskValue)
|
|
{
|
|
OptionArgument = optionArgument;
|
|
GetValue = (e) => optionValue;
|
|
MaskValue = maskValue;
|
|
}
|
|
public Option(string optionArgument, Func<CommandEnvironment,string> getOptionValue) : this(optionArgument, getOptionValue, false) { }
|
|
public Option(string optionArgument, Func<CommandEnvironment,string> getOptionValue, bool maskValue)
|
|
{
|
|
OptionArgument = optionArgument;
|
|
GetValue = getOptionValue;
|
|
MaskValue = maskValue;
|
|
}
|
|
|
|
public override string[] GetArguments(CommandEnvironment environment, bool mask)
|
|
{
|
|
string value = GetValue(environment);
|
|
if ((value == null) || String.Empty.Equals(value))
|
|
{
|
|
return new string[0];
|
|
} else {
|
|
return new string[]{ OptionArgument, (mask && MaskValue) ? "*****" : value };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |