Esempio n. 1
0
        /// <summary>
        /// Performs the completion work for Async workers, and is called
        /// after the runAsync method returns.  Returns the ultimate
        /// disposition of the activity.
        /// </summary>
        /// <remarks>
        /// This method runs synchronously on the main thread.
        /// It can tidy up the state after async work, and store results
        /// in the Repository.
        /// Thou shalt not return Stale.
        /// </remarks>
        /// <returns>The disposition of this verb's worker's work.</returns>
        public Disposition Complete()
        {
            this.verb.RecordProcessInvokeCpuTime(this.pinv.CpuTime);

            string stdout = null;

            if (this.returnStandardOut)
            {
                stdout = this.pinv.GetStdout();
            }

            string stderr = null;

            if (this.returnStandardError)
            {
                stderr = this.pinv.GetStderr();
            }

            Disposition disposition;

            if (this.exitCodeHandling == ProcessExitCodeHandling.NonzeroIsOkay || this.pinv.ExitCode == 0)
            {
                disposition = new Fresh();
            }
            else
            {
                // Sheesh. Some tools emit error messages to stdout.
                // REVIEW: Provide full command line here rather than just executable (like old version did)?
                Failed f = new Failed(this.pinv.GetStdout() + this.pinv.GetStderr());
                f.AddError("Executable: " + this.executable + "\n");
                disposition = f;
            }

            return(this.verb.Complete(this.workingDirectory, this.pinv.CpuTime, stdout, stderr, disposition));
        }
        /// <summary>
        /// Performs the completion work for Async workers, and is called
        /// after the runAsync method returns.  Returns the ultimate
        /// disposition of the activity.
        /// </summary>
        /// <remarks>
        /// This method runs synchronously on the main thread.
        /// It can tidy up the state after async work, and store results
        /// in the Repository.
        /// Thou shalt not return Stale.
        /// </remarks>
        /// <returns>The disposition of this verb's worker's work.</returns>
        public Disposition Complete()
        {
            this.verb.RecordProcessInvokeCpuTime(this.pinv.CpuTime);

            string stdout = null;
            if (this.returnStandardOut)
            {
                stdout = this.pinv.GetStdout();
            }

            string stderr = null;
            if (this.returnStandardError)
            {
                stderr = this.pinv.GetStderr();
            }

            Disposition disposition;
            if (this.exitCodeHandling == ProcessExitCodeHandling.NonzeroIsOkay || this.pinv.ExitCode == 0)
            {
                disposition = new Fresh();
            }
            else
            {
                // Sheesh. Some tools emit error messages to stdout.
                // REVIEW: Provide full command line here rather than just executable (like old version did)?
                Failed f = new Failed(this.pinv.GetStdout() + this.pinv.GetStderr());
                f.AddError("Executable: " + this.executable + "\n");
                disposition = f;
            }

            return this.verb.Complete(this.workingDirectory, this.pinv.CpuTime, stdout, stderr, disposition);
        }
Esempio n. 3
0
        public ProcessInvoker(
            string executable,
            string[] args,
            RcHandling rcHandling,
            BuildObject failureBase,
            string finalStdoutPath = null,
            string dbgText         = null,
            bool allowAbsoluteExe  = false,
            bool allowAbsoluteArgs = false,
            string workingDir      = null)
        {
            Util.Assert(allowAbsoluteExe || !executable.Contains(":"));  //- Hey, this looks like an absolute path! Use .getRelativePath() to tolerate crossing machine boundaries.
            foreach (string arg in args)
            {
                //- Pardon my distasteful heuristic to avoid flagging /flag:value args.
                Util.Assert(allowAbsoluteArgs || arg.Length < 2 || arg[1] != ':');  //- Hey, this looks like an absolute path! Use .getRelativePath() to tolerate crossing machine boundaries.
            }

            this.rcHandling = rcHandling;
            stdout          = new StringBuilder();
            stderr          = new StringBuilder();

            using (Job job = new Job())
            {
                using (Process proc = new Process())
                {
                    proc.StartInfo.FileName = Path.Combine(BuildEngine.theEngine.getIronRoot(), executable);
                    //- TODO Is there a better way to escape the args to avoid problems with spaces?
                    proc.StartInfo.Arguments = String.Join(" ", args);

                    proc.StartInfo.WorkingDirectory = workingDir == null?BuildEngine.theEngine.getIronRoot() : workingDir;

                    proc.StartInfo.RedirectStandardOutput = true;
                    if (finalStdoutPath != null)
                    {
                        _tmpStdoutPath           = finalStdoutPath + ".tmp";
                        stdoutFile               = new StreamWriter(_tmpStdoutPath);
                        proc.OutputDataReceived += new DataReceivedEventHandler(stdoutRedirectHandler);
                    }
                    else
                    {
                        //- collect stdout here for diagnostics.
                        proc.OutputDataReceived += new DataReceivedEventHandler(stdoutHandler);
                    }
                    proc.StartInfo.RedirectStandardError = true;
                    proc.ErrorDataReceived        += new DataReceivedEventHandler(stderrHandler);
                    proc.StartInfo.UseShellExecute = false;

                    string commandLine = proc.StartInfo.FileName + " " + proc.StartInfo.Arguments;
                    if (alwaysEmitDiagnostics)
                    {
                        //- In diagnostic mode, we emit the command line twice, once ahead in case Boogie decides
                        //- to run away and never come back.
                        BuildObject failureBatObj = failureBase.makeOutputObject(".bat");
                        failureBatObj.prepareObjDirectory();
                        File.WriteAllText(failureBatObj.getFilesystemPath(), commandLine);
                    }

                    proc.Start();
                    job.AddProcess(proc);
                    proc.BeginOutputReadLine();
                    proc.BeginErrorReadLine();
                    proc.WaitForExit();

                    cpuTime = job.GetCpuTime().TotalSeconds;

                    exitCode = proc.ExitCode;
                    if (stdoutFile != null)
                    {
                        stdoutFile.Close();
                    }

                    if (passed())
                    {
                        disposition = new Fresh();
                    }
                    else
                    {
                        //- sheesh. Some tools emit error messages to stdout.
                        Failed f = new Failed(getStdoutString() + stderr.ToString());
                        f.AddError("Command line: " + commandLine + "\n");
                        disposition = f;
                    }

#pragma warning disable 429 //- alwaysEmitDiagnostics is a compile-time constant that can hide expression !passed()
                    if (failureBase != null && (alwaysEmitDiagnostics || !passed()))
#pragma warning restore 429
                    {
                        failureBase.prepareObjDirectory();
                        File.WriteAllText(failureBase.makeOutputObject(".bat").getFilesystemPath(), commandLine);
                        File.WriteAllText(failureBase.makeOutputObject(".txt").getFilesystemPath(), dbgText);
                        File.WriteAllText(failureBase.makeOutputObject(".stdout").getFilesystemPath(), getStdoutString());
                        File.WriteAllText(failureBase.makeOutputObject(".stderr").getFilesystemPath(), getStderr());
                    }
                }
            }

            if (passed() && _tmpStdoutPath != null)
            {
                File.Delete(finalStdoutPath);
                File.Move(_tmpStdoutPath, finalStdoutPath);
                _tmpStdoutPath = null;
            }
        }