/******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2003, ThoughtWorks, Inc. * 200 E. Randolph, 25th Floor * Chicago, IL 60601 USA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * + Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************/ package net.sourceforge.cruisecontrol.builders; import java.util.List; import net.sourceforge.cruisecontrol.CruiseControlException; import net.sourceforge.cruisecontrol.Progress; import net.sourceforge.cruisecontrol.util.Commandline; import net.sourceforge.cruisecontrol.util.OSEnvironment; import net.sourceforge.cruisecontrol.util.StreamConsumer; import org.apache.log4j.Logger; import org.jdom.CDATA; import org.jdom.Element; /** * Exec script class. Script support to execute a command and logs the results. * * @author <a href="mailto:kevin.lee@buildmeister.com">Kevin Lee</a> */ public class ExecScript implements Script, StreamConsumer { private static final Logger LOG = Logger.getLogger(ExecScript.class); private String execCommand; private String execArgs; private String errorStr; private OSEnvironment execEnv; private Progress progress; private int exitCode; private boolean foundError; private Element buildLogElement; private Element currentElement; /** * construct the command that we're going to execute. * * @return Commandline holding command to be executed * @throws CruiseControlException */ public Commandline buildCommandline() throws CruiseControlException { Commandline cmdLine = new Commandline(); // make sure we have a command if (execCommand != null) { cmdLine.setExecutable(execCommand); } else { throw new CruiseControlException("no command to be executed"); } // add the arguments if necessary if (execArgs != null) { cmdLine.addArguments(Commandline.translateCommandline(execArgs)); } // add the environment values if necessary if (execEnv != null) { cmdLine.setEnv(this.execEnv); } // log the command if debug is enabled if (LOG.isDebugEnabled()) { final StringBuilder sb = new StringBuilder(); sb.append("Executing Command: "); final String[] args = cmdLine.getCommandline(); for (final String arg : args) { sb.append(arg); sb.append(" "); } LOG.debug(sb.toString()); } return cmdLine; } // buildCommandLine /** * StreamConsumer.consumeLine(String), Called from StreamPumper. * * @param line * the line of output to parse */ public synchronized void consumeLine(final String line) { if (line == null || line.length() == 0 || buildLogElement == null) { return; } final Element message; final String messageLevel; if (errorStr != null && line.contains(errorStr)) { foundError = true; messageLevel = "error"; message = messageFromLine(line, messageLevel); } else { messageLevel = "info"; message = messageFromLine(line, messageLevel); } synchronized (buildLogElement) { if (currentElement == null) { buildLogElement.addContent(message); } else { currentElement.addContent(message); } } if (progress != null) { progress.setValue(line); } } private Element messageFromLine(final String line, String level) { final Element msg = new Element("message"); msg.addContent(new CDATA(line)); msg.setAttribute("priority", level); return msg; } /** * flush the current log element */ protected void flushCurrentElement() { if (buildLogElement == null) { return; } synchronized (buildLogElement) { if (currentElement != null) { if (buildLogElement.getAttribute("error") != null) { // All the messages of the last (failed) goal should be // switched to priority error final List lst = currentElement.getChildren("message"); if (lst != null) { for (final Object aLst : lst) { final Element msg = (Element) aLst; msg.setAttribute("priority", "error"); } } } buildLogElement.addContent(currentElement); } currentElement = null; } } // flushCurrentElement /** * set the "header" for this part of the build log. turns it into an Ant target/task style element for reporting * purposes * * @param buildLogElement * the element of the build log * @return updated element */ public Element setBuildLogHeader(Element buildLogElement) { Element target = new Element("target"); target.setAttribute("name", "exec"); buildLogElement.addContent(target); Element task = new Element("task"); task.setAttribute("name", this.execCommand); target.addContent(task); return task; } // setBuildLogHeader /** * @param execArgs * The execArgs to set. */ public void setExecArgs(String execArgs) { this.execArgs = execArgs; } // setExecArgs /** * @param execCommand * The execCommand to set. */ public void setExecCommand(String execCommand) { this.execCommand = execCommand; } // setExecCommand /** * @param env * The environment variables of the script, or <code>null</code> if to * inherit the environment of the current process */ public void setExecEnv(final OSEnvironment env) { this.execEnv = env; } // setExecEnv /** * @return returns the exitcode of the command */ public int getExitCode() { return exitCode; } // getExitCode /** * @param exitCode * the exit code value to set. */ public void setExitCode(int exitCode) { this.exitCode = exitCode; } // setExitCode /** * @param errStr * the error string to search for */ public void setErrorStr(String errStr) { this.errorStr = errStr; } // setErrorStr /** * @param buildLogElement * The buildLogElement to set. */ public void setBuildLogElement(Element buildLogElement) { this.buildLogElement = buildLogElement; } // setBuildLogElement /** @param progress The progress callback object to set. */ public void setProgress(final Progress progress) { this.progress = progress; } /** * @return true if error occurred, else false */ public boolean wasError() { return this.foundError; } // wasError } // ExecScript