Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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"
                });
            }
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }