public static SMVActionResult ExecuteAction()

in SmvLibrary/Utility.cs [444:662]


        public static SMVActionResult ExecuteAction(SMVAction action, bool fromWorker, bool workerUseDb, string workerTaskId)
        {

            // NOTE: The code in this function must be thread safe.
            if (action == null)
            {
                return null;
            }

            // If there is a plugin, call PreAction first.
            if (plugin != null)
            {
                plugin.PreAction(action);
            }

            if (fromWorker)
            {
                taskId = workerTaskId;
            }

            using (MemoryStream stream = new MemoryStream())
            {
                // We use a logger for writing messages since we can't output to the console in this function (As this
                // may be running in multiple threads).
                StreamWriter logger = new StreamWriter(stream);
                IDictionary<string, string> variables = action.variables;
                DateTime startTime = DateTime.Now;
                string actionPath = variables["workingDir"];
                string actionOutput = string.Empty;
                int cumulativeExitCode = 0;

                // Get the name of the action.
                string name = action.name;
                if (variables.ContainsKey("analysisProperty"))
                {
                    name = action.name + " - " + variables["analysisProperty"];
                }
                variables["name"] = action.name;
                Log.LogInfo("Running action: " + name, logger);

                // Get the path to the action.
                if (action.Path != null)
                {
                    actionPath = action.Path.value;
                }
                actionPath = ExpandVariables(actionPath, variables);
                variables["actionPath"] = actionPath;

                // Launch a cmd.exe process to run commands in.
                if (Console.InputEncoding.Equals(Encoding.UTF8))
                {
                    Console.InputEncoding = new UTF8Encoding(false);
                }


                // Run the commands.
                if (action.Command != null)
                {
                    foreach (SMVCommand cmd in action.Command)
                    {
                        JobObject jobObject = null;
                        if (useJobObject)
                        {
                            //Update maxTime and maxMemory allowed
                            int maxMemory = int.MaxValue;
                            int maxTime = int.MaxValue;
                            updateAttribute(ref maxTime, cmd.maxTime, "Time");
                            Log.LogDebug("Maximum time allowed for this command = " + maxTime);
                            updateAttribute(ref maxMemory, cmd.maxMemory, "Memory");

                            //Converting memory from MB to bytes, if input is valid
                            if (maxMemory < int.MaxValue)
                            {
                                maxMemory *= (1024 * 1024);
                            }
                            Log.LogDebug("Maximum memory allowed for this command = " + maxMemory);
                            jobObject = new JobObject();
                            jobObject.setConstraints(maxMemory, maxTime);
                        }
                        Process process = LaunchProcess("cmd.exe", "", actionPath, action.Env, logger, jobObject);
                        process.OutputDataReceived += (sender, e) => { Log.LogMessage(e.Data, logger); };
                        process.ErrorDataReceived += (sender, e) => { Log.LogMessage(e.Data, logger); };

                        // Get the command and arguments, and expand all environment as well as SMV variables.
                        string cmdAttr = ExpandVariables(Environment.ExpandEnvironmentVariables(cmd.value), variables);
                        string argumentsAttr = string.Empty;
                        if (!string.IsNullOrEmpty(cmd.arguments))
                        {
                            argumentsAttr = ExpandVariables(Environment.ExpandEnvironmentVariables(cmd.arguments), variables);
                        }

                        try
                        {
                            Log.LogInfo(String.Format(CultureInfo.InvariantCulture, "Launching {0} with arguments: {1}", cmdAttr, argumentsAttr), logger);
                            process.StandardInput.WriteLine(String.Join(" ", new String[] { cmdAttr, argumentsAttr }));
                            process.StandardInput.WriteLine("Exit %errorlevel%");
                            process.StandardInput.Close();
                            process.BeginOutputReadLine();
                            process.BeginErrorReadLine();
                            process.WaitForExit();
                            TimeSpan span = process.ExitTime - process.StartTime;
                            Log.LogMessage(string.Format("Command Exit code: {0}", process.ExitCode), logger);
                            cumulativeExitCode += Math.Abs(process.ExitCode);
                            if (useDb || (fromWorker && workerUseDb))
                            {
                                try
                                {
                                    using (var database = new SmvDbEntities())
                                    {
                                        var masterEntry = new TaskAction
                                        {
                                            ActionID = Guid.NewGuid().ToString(),
                                            TaskID = taskId,
                                            ActionName = action.name,
                                            Success = cumulativeExitCode.ToString(),
                                            ActionTime = span.ToString(),
                                            WorkingDirectory = variables["workingDir"],
                                            AnalysisDirectory = variables["analysisProperty"]
                                        };
                                        database.TaskActions.Add(masterEntry);
                                        database.SaveChanges();
                                    }
                                }
                                catch (Exception e)
                                {
                                    if (fromWorker)
                                    {
                                        Log.LogError("Exception while updating database " + e);
                                    }
                                    else
                                    {
                                        scheduler.Dispose();
                                        Log.LogFatalError("Exception while updating database " + e);
                                    }
                                }

                            }
                            if (useJobObject)
                            {
                                jobObject.QueryExtendedLimitInformation();
                                jobObject.Close();
                                jobObject.Dispose();
                            }
                        }
                        catch (Exception e)
                        {
                            Log.LogInfo(e.ToString(), logger);
                            Log.LogInfo("Could not start process: " + cmdAttr, logger);
                            if (useJobObject)
                            {
                                jobObject.Close();
                                jobObject.Dispose();
                            }
                            return null;
                        }
                    }

                }

                logger.Flush();
                stream.Position = 0;
                string output = new StreamReader(stream).ReadToEnd();

                if (debugMode)
                {
                    Log.WriteToFile(Path.Combine(actionPath, string.Format("smvexecute-{0}.log", action.name)), output, false);
                }
                Log.LogDebug("cumulative exit code is " + cumulativeExitCode);

                DateTime endTime = DateTime.Now;

                action.result = new SMVActionResult(action.name, output, (cumulativeExitCode == 0),
                    cumulativeExitCode != 0 && action.breakOnError, (int)(endTime - startTime).TotalSeconds);

                // Call plugin post action only if we were successful in executing the action.
                if (cumulativeExitCode == 0)
                {
                    // get the output directory and set the output of the action from the build log.
                    if (action.name.Equals("NormalBuild"))
                    {
                        string logPath = Path.Combine(variables["workingDir"], variables["smvLogFileNamePrefix"] + ".log");
                        action.result.output = Utility.ReadFile(logPath);
                        if (!variables.ContainsKey("outputDir")){
                            variables["outputDir"] = ExtractBuildPath(variables["workingDir"], action.result.output, logger);
                            Utility.SetSmvVar("outputDir", variables["outputDir"]);
                        }
                    }

                    // Get the output directory and the analysis directory.
                    if (action.name.Equals("InterceptedBuild"))
                    {
                        string logPath = Path.Combine(variables["workingDir"], variables["smvLogFileNamePrefix"] + ".log");
                        action.result.output = Utility.ReadFile(logPath);
                    }

                    // Call the plugin's post action.
                    if (plugin != null)
                    {
                        plugin.PostAction(action);
                    }
                }
                else
                {
                    // are we sure we want to exit here... the cloud worker instance becomes 
                    // unhealthy after exiting here...
                    if (action.breakOnError)
                    {
                        if (!fromWorker)
                        {
                            scheduler.Dispose();
                            plugin.Finally(true);
                            Log.LogFatalError(String.Format("Action: {0}, failed.", name));
                        }
                    }
                }

                return action.result;
            }
        }