static void PrintOptions(Opts opts) { Log log = Log.GetLogger(); log.dbgKeyVal("filename input", opts.inputfilename); log.dbgKeyVal("filename stdout", opts.filenameStdout); log.dbgKeyVal("filename stderr", opts.filenameStderr); }
private static void ExpandCommand(Opts opts, ref List <string> commandTemplate) { if (commandTemplate == null || commandTemplate?.Count == 0) { return; } if (opts.runCmdExe || commandTemplate[0].EndsWith(".bat", StringComparison.OrdinalIgnoreCase) || commandTemplate[0].EndsWith(".cmd", StringComparison.OrdinalIgnoreCase)) { commandTemplate.InsertRange(0, new string[] { Environment.GetEnvironmentVariable("ComSpec"), "/c" }); } else if (commandTemplate[0].EndsWith(".vbs", StringComparison.OrdinalIgnoreCase)) { commandTemplate.InsertRange(0, new string[] { Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "system32", "cscript.exe"), "//NOLOGO" }); } }
public static bool ParseOpts(string[] args, out Opts opts, out List <string> commandlineTemplate) { opts = null; bool showhelp = false; string defaultOutFilename = @".\forp.out.txt"; Opts tmpOpts = new Opts() { }; var cmdOpts = new BeeOptsBuilder() .Add('f', "file", OPTTYPE.VALUE, "input file", o => tmpOpts.inputfilename = o) .Add('c', "cmd", OPTTYPE.BOOL, "execute with [%ComSpec% /C]", o => tmpOpts.runCmdExe = true) .Add('o', "out", OPTTYPE.VALUE, $"filename for stdout. default: {defaultOutFilename}", o => tmpOpts.filenameStdout = o) .Add('e', "err", OPTTYPE.VALUE, $"filename for stderr. default: {defaultOutFilename}", o => tmpOpts.filenameStderr = o) .Add('1', "first", OPTTYPE.BOOL, "run only for first line in inputfile", o => tmpOpts.firstOnly = true) .Add('n', "dryrun", OPTTYPE.BOOL, "dry run", o => tmpOpts.dryrun = true) .Add('s', "skipempty", OPTTYPE.BOOL, "do not write empty lines to output. String.IsNullOrWhiteSpace()", o => tmpOpts.skipEmptyLines = true) .Add('q', "quiet", OPTTYPE.BOOL, "don't print anything", o => tmpOpts.quiet = true) .Add('x', "parallel", OPTTYPE.VALUE, $"run max parallel processes (default: {tmpOpts.maxParallel})", o => tmpOpts.maxParallel = Convert.ToInt32(o)) .Add('d', "debug", OPTTYPE.BOOL, "debug output", o => tmpOpts.debug = true) .Add('h', "help", OPTTYPE.BOOL, "show help", o => showhelp = true) .Add(null, "stdout", OPTTYPE.BOOL, "write stdout/stderr of processes to stdout", o => tmpOpts.allToStdout = true) .Add(null, "noprefix", OPTTYPE.BOOL, "do not prefix every output line with %1", o => tmpOpts.printPrefix = false) .Add(null, "noerr", OPTTYPE.BOOL, "do not capture stderr", o => tmpOpts.writeStderr = false) .GetOpts(); commandlineTemplate = Spi.BeeOpts.Parse(args, cmdOpts, (string unknownOpt) => Console.Error.WriteLine($"unknow option [{unknownOpt}]")); if (showhelp) { Console.WriteLine( "\nusage: forp.exe [OPTIONS] -- [commandline to execute. use %1, %2, ... as tokens from your input]" + "\n\nOptions:"); Spi.BeeOpts.PrintOptions(cmdOpts); Console.WriteLine( "\n + if no inputfile is given. read input from stdin" + "\n + each line from the input is parsed with CommandLineToArgv() to produce %1, %2, ..." + "\n\n generated files:" + "\n + forp.out.txt ........ stdout and stderr from all executed processes. each line is prepended with %1" + "\n + forp.ExitCode.txt ... exitcode of each executed process. {rc}TAB{commandline}" + "\n\n defaults:" + "\n 1, if just one program (exe/...) is passed as commandline, all the tokens form your input will be appended to it" + "\n 2, if no commandline is given the lines of your input are treated as a commandline to execute" ); return(false); } if (!String.IsNullOrEmpty(tmpOpts.inputfilename)) { if (!File.Exists(tmpOpts.inputfilename)) { Console.Error.WriteLine($"cannot find inputfile given [{tmpOpts.inputfilename}]"); return(false); } } if (tmpOpts.allToStdout) { if (!(String.IsNullOrEmpty(tmpOpts.filenameStdout) && String.IsNullOrEmpty(tmpOpts.filenameStderr))) { Console.Error.WriteLine($"you have specified to write everything to stdout, but also give a filename for out/err."); return(false); } } else { if (tmpOpts.writeStderr) { } else { if (!String.IsNullOrEmpty(tmpOpts.filenameStderr)) { Console.Error.WriteLine($"you have specified NOT TO WRITE stderr but a filename of [{tmpOpts.filenameStderr}] was given."); return(false); } } if (String.IsNullOrEmpty(tmpOpts.filenameStdout)) { tmpOpts.filenameStdout = defaultOutFilename; } } opts = tmpOpts; return(true); }
static int Main(string[] args) { if (!Opts.ParseOpts(args, out Opts opts, out List <string> commandTemplate)) { return(1); } if (opts.debug) { Log.SetLevel(Log.LEVEL.DEBUG); } Log log = Log.GetLogger(); PrintOptions(opts); ThreadPool.GetMaxThreads(out int maxwork, out int maxio); ThreadPool.GetMinThreads(out int minwork, out int minio); log.dbg("minWork: {0}, minIO: {1}, maxWork: {2}, maxIO: {3}", minwork, minio, maxwork, maxio); if (ThreadPool.SetMaxThreads(minwork, minio)) { log.dbg("successfully set MaxThreads to {0}/{1}", minwork, minio); } // // must be placed here. afterwards commandtemplate get's expanded // bool appendAllInputTokens = commandTemplate.Count == 0 || (commandTemplate.Count == 1 && !Misc.isPercentTokenNumber(commandTemplate[0])); ExpandCommand(opts, ref commandTemplate); log.dbgKeyVal("CommandTemplate", String.Join(" ", commandTemplate)); TextReader inputstream; Func <long> jobCount; if (String.IsNullOrEmpty(opts.inputfilename)) { jobCount = null; inputstream = Console.In; log.dbg("reading from stdin"); } else { inputstream = new StreamReader(opts.inputfilename); jobCount = () => { using (var linereader = new StreamReader(new FileStream(opts.inputfilename, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))) { return(Misc.ReadLines(linereader).LongCount()); } }; } using (inputstream) { IEnumerable <ProcCtx> commandlines2Exec = ConstructCommandline(opts.printPrefix, commandTemplate, inputstream, appendAllInputTokens); if (opts.firstOnly) { commandlines2Exec = commandlines2Exec.Take(1); } if (opts.dryrun) { foreach (var p in commandlines2Exec) { Console.Out.WriteLine(p.commandline); } } else { GetOutErrStreams(opts.filenameStdout, opts.filenameStderr, out TextWriter outStream, out TextWriter errStream); long start = DateTime.Now.Ticks; Stats stats = null; using (outStream) using (errStream) { stats = forp.Run(commandlines2Exec, outStream, errStream, opts.maxParallel, opts.skipEmptyLines, opts.quiet, opts.writeStderr, jobCount); } if (!opts.quiet) { TimeSpan forpDuration = new TimeSpan(DateTime.Now.Ticks - start); Console.Error.WriteLine( "executed processes:" + $"\n TotalTime: {new TimeSpan(stats.procTotalTime)}" + $"\n KernelTime: {new TimeSpan(stats.procKernelTime)}" + $"\n UserTime: {new TimeSpan(stats.procUserTime)}" + $"\nforp duration: {forpDuration}"); } } } return(0); }