| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.ant.svn; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.PrintStream; |
| import java.util.Vector; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.taskdefs.Execute; |
| import org.apache.tools.ant.taskdefs.ExecuteStreamHandler; |
| import org.apache.tools.ant.taskdefs.LogOutputStream; |
| import org.apache.tools.ant.taskdefs.PumpStreamHandler; |
| import org.apache.tools.ant.types.Commandline; |
| import org.apache.tools.ant.types.Environment; |
| import org.apache.tools.ant.util.StringUtils; |
| |
| /** |
| * Just like Ant's built-in CVS task, the main loginc lives in this |
| * abstract task. |
| */ |
| public abstract class AbstractSvnTask extends Task { |
| |
| private Commandline cmd = new Commandline(); |
| |
| /** list of Commandline children */ |
| private Vector vecCommandlines = new Vector(); |
| |
| /** |
| * the URL the subcommand should apply to. |
| */ |
| private String svnURL; |
| |
| /** |
| * the revision |
| */ |
| private String revision; |
| /** |
| * the default command. |
| */ |
| private static final String DEFAULT_SUBCOMMAND = "checkout"; |
| /** |
| * the SVN command to execute. |
| */ |
| private String subCommand = null; |
| |
| /** |
| * suppress information messages. |
| */ |
| private boolean quiet = false; |
| |
| /** |
| * be verbose |
| */ |
| private boolean verbose = false; |
| |
| /** |
| * report only, don't change any files. |
| */ |
| private boolean dryrun = false; |
| |
| /** |
| * the directory where the checked out files should be placed. |
| */ |
| private File dest; |
| |
| /** whether or not to append stdout/stderr to existing files */ |
| private boolean append = false; |
| |
| /** |
| * the file to direct standard output from the command. |
| */ |
| private File output; |
| |
| /** |
| * the file to direct standard error from the command. |
| */ |
| private File error; |
| |
| /** |
| * If true it will stop the build if svn exits with error. |
| * Default is false. (Iulian) |
| */ |
| private boolean failOnError = false; |
| |
| /** |
| * Uses the contents of the file passed as an argument to this |
| * switch for the specified subcommand. |
| */ |
| private File file; |
| |
| /** |
| * Forces a particular command or operation to run. |
| */ |
| private boolean force; |
| |
| /** |
| * Makes a subcommand recurse into subdirectories. |
| */ |
| private Boolean recursive = null; |
| |
| /** |
| * Tells Subversion to get the list of files that you wish to |
| * operate on from the filename you provide instead of listing all |
| * the files on the command line. |
| */ |
| private File targets; |
| |
| /** |
| * Create accessors for the following, to allow different handling of |
| * the output. |
| */ |
| private ExecuteStreamHandler executeStreamHandler; |
| private OutputStream outputStream; |
| private OutputStream errorStream; |
| |
| /** empty no-arg constructor*/ |
| public AbstractSvnTask() { |
| super(); |
| } |
| |
| /** |
| * sets the handler |
| * @param handler a handler able of processing the output and error streams from the svn exe |
| */ |
| public void setExecuteStreamHandler(ExecuteStreamHandler handler) { |
| this.executeStreamHandler = handler; |
| } |
| |
| /** |
| * find the handler and instantiate it if it does not exist yet |
| * @return handler for output and error streams |
| */ |
| protected ExecuteStreamHandler getExecuteStreamHandler() { |
| |
| if (this.executeStreamHandler == null) { |
| setExecuteStreamHandler(new PumpStreamHandler(getOutputStream(), |
| getErrorStream())); |
| } |
| |
| return this.executeStreamHandler; |
| } |
| |
| /** |
| * sets a stream to which the output from the svn executable should be sent |
| * @param outputStream stream to which the stdout from svn should go |
| */ |
| protected void setOutputStream(OutputStream outputStream) { |
| |
| this.outputStream = outputStream; |
| } |
| |
| /** |
| * access the stream to which the stdout from svn should go |
| * if this stream has already been set, it will be returned |
| * if the stream has not yet been set, if the attribute output |
| * has been set, the output stream will go to the output file |
| * otherwise the output will go to ant's logging system |
| * @return output stream to which svn' stdout should go to |
| */ |
| protected OutputStream getOutputStream() { |
| |
| if (this.outputStream == null) { |
| |
| if (output != null) { |
| try { |
| setOutputStream(new PrintStream( |
| new BufferedOutputStream( |
| new FileOutputStream(output |
| .getPath(), |
| append)))); |
| } catch (IOException e) { |
| throw new BuildException(e, getLocation()); |
| } |
| } else { |
| setOutputStream(new LogOutputStream(this, Project.MSG_INFO)); |
| } |
| } |
| |
| return this.outputStream; |
| } |
| |
| /** |
| * sets a stream to which the stderr from the svn exe should go |
| * @param errorStream an output stream willing to process stderr |
| */ |
| protected void setErrorStream(OutputStream errorStream) { |
| |
| this.errorStream = errorStream; |
| } |
| |
| /** |
| * access the stream to which the stderr from svn should go |
| * if this stream has already been set, it will be returned |
| * if the stream has not yet been set, if the attribute error |
| * has been set, the output stream will go to the file denoted by the error attribute |
| * otherwise the stderr output will go to ant's logging system |
| * @return output stream to which svn' stderr should go to |
| */ |
| protected OutputStream getErrorStream() { |
| |
| if (this.errorStream == null) { |
| |
| if (error != null) { |
| |
| try { |
| setErrorStream(new PrintStream( |
| new BufferedOutputStream( |
| new FileOutputStream(error.getPath(), |
| append)))); |
| } catch (IOException e) { |
| throw new BuildException(e, getLocation()); |
| } |
| } else { |
| setErrorStream(new LogOutputStream(this, Project.MSG_WARN)); |
| } |
| } |
| |
| return this.errorStream; |
| } |
| |
| /** |
| * Sets up the environment for toExecute and then runs it. |
| * @param toExecute the command line to execute |
| * @throws BuildException if failonError is set to true and the svn command fails |
| */ |
| protected void runCommand(Commandline toExecute) throws BuildException { |
| Environment env = new Environment(); |
| |
| // |
| // Just call the getExecuteStreamHandler() and let it handle |
| // the semantics of instantiation or retrieval. |
| // |
| Execute exe = new Execute(getExecuteStreamHandler(), null); |
| |
| exe.setAntRun(getProject()); |
| if (dest == null) { |
| dest = getProject().getBaseDir(); |
| } |
| |
| if (!dest.exists()) { |
| dest.mkdirs(); |
| } |
| |
| exe.setWorkingDirectory(dest); |
| exe.setCommandline(toExecute.getCommandline()); |
| exe.setEnvironment(env.getVariables()); |
| |
| try { |
| String actualCommandLine = executeToString(exe); |
| log(actualCommandLine, Project.MSG_VERBOSE); |
| int retCode = exe.execute(); |
| log("retCode=" + retCode, Project.MSG_DEBUG); |
| /*Throw an exception if svn exited with error. (Iulian)*/ |
| if (failOnError && Execute.isFailure(retCode)) { |
| throw new BuildException("svn exited with error code " |
| + retCode |
| + StringUtils.LINE_SEP |
| + "Command line was [" |
| + actualCommandLine + "]", getLocation()); |
| } |
| } catch (IOException e) { |
| if (failOnError) { |
| throw new BuildException(e, getLocation()); |
| } else { |
| log("Caught exception: " + e.getMessage(), Project.MSG_WARN); |
| } |
| } catch (BuildException e) { |
| if (failOnError) { |
| throw(e); |
| } else { |
| Throwable t = e.getException(); |
| if (t == null) { |
| t = e; |
| } |
| log("Caught exception: " + t.getMessage(), Project.MSG_WARN); |
| } |
| } catch (Exception e) { |
| if (failOnError) { |
| throw new BuildException(e, getLocation()); |
| } else { |
| log("Caught exception: " + e.getMessage(), Project.MSG_WARN); |
| } |
| } |
| } |
| |
| /** |
| * do the work |
| * @throws BuildException if failonerror is set to true and the svn command fails. |
| */ |
| public void execute() throws BuildException { |
| |
| String savedCommand = getSubCommand(); |
| |
| if (this.getSubCommand() == null && vecCommandlines.size() == 0) { |
| // re-implement legacy behaviour: |
| this.setSubCommand(AbstractSvnTask.DEFAULT_SUBCOMMAND); |
| } |
| |
| String c = this.getSubCommand(); |
| Commandline cloned = null; |
| if (c != null) { |
| cloned = (Commandline) cmd.clone(); |
| cloned.createArgument(true).setLine(c); |
| if (svnURL != null) { |
| cloned.createArgument().setValue(svnURL); |
| } |
| this.addConfiguredCommandline(cloned, true); |
| } |
| |
| try { |
| for (int i = 0; i < vecCommandlines.size(); i++) { |
| this.runCommand((Commandline) vecCommandlines.elementAt(i)); |
| } |
| } finally { |
| if (cloned != null) { |
| removeCommandline(cloned); |
| } |
| setSubCommand(savedCommand); |
| |
| if (outputStream != null) { |
| try { |
| outputStream.close(); |
| } catch (IOException e) { |
| //ignore |
| } |
| } |
| if (errorStream != null) { |
| try { |
| errorStream.close(); |
| } catch (IOException e) { |
| //ignore |
| } |
| } |
| } |
| } |
| |
| private String executeToString(Execute execute) { |
| |
| StringBuffer stringBuffer = |
| new StringBuffer(Commandline.describeCommand(execute |
| .getCommandline())); |
| |
| String newLine = StringUtils.LINE_SEP; |
| String[] variableArray = execute.getEnvironment(); |
| |
| if (variableArray != null) { |
| stringBuffer.append(newLine); |
| stringBuffer.append(newLine); |
| stringBuffer.append("environment:"); |
| stringBuffer.append(newLine); |
| for (int z = 0; z < variableArray.length; z++) { |
| stringBuffer.append(newLine); |
| stringBuffer.append("\t"); |
| stringBuffer.append(variableArray[z]); |
| } |
| } |
| |
| return stringBuffer.toString(); |
| } |
| |
| /** |
| * The URL the subcommand should apply to. |
| * |
| * @param url the URL the subcommand should apply to. |
| */ |
| public void setSvnURL(String url) { |
| |
| // Check if not real svnroot => set it to null |
| if (url != null) { |
| if (url.trim().equals("")) { |
| url = null; |
| } |
| } |
| |
| this.svnURL = url; |
| } |
| |
| /** |
| * access the svnURL variable |
| * @return svnURL |
| */ |
| public String getSvnURL() { |
| |
| return this.svnURL; |
| } |
| |
| /** |
| * The directory where the checked out files should be placed. |
| * |
| * <p>Note that this is different from SVN's -d command line |
| * switch as Ant will never shorten pathnames to avoid empty |
| * directories.</p> |
| * |
| * @param dest directory where the checked out files should be placed |
| */ |
| public void setDest(File dest) { |
| this.dest = dest; |
| } |
| |
| /** |
| * get the file where the checked out files should be placed |
| * |
| * @return directory where the checked out files should be placed |
| */ |
| public File getDest() { |
| |
| return this.dest; |
| } |
| |
| /** |
| * revision |
| * @return revision |
| */ |
| public String getRevision() { |
| return revision; |
| } |
| |
| /** |
| * The revision to operate upon. |
| * @param p revision |
| */ |
| public void setRevision(String p) { |
| // Check if not real revision => set it to null |
| if (p != null && p.trim().length() > 0) { |
| revision = p; |
| addSubCommandArgument("--revision"); |
| addSubCommandArgument(p); |
| } |
| } |
| |
| /** |
| * Uses the contents of the file passed as an argument to this |
| * switch for the specified subcommand. |
| */ |
| public void setFile(File file) { |
| this.file = file; |
| } |
| |
| /** |
| * Uses the contents of the file passed as an argument to this |
| * switch for the specified subcommand. |
| */ |
| public File getFile() { |
| return file; |
| } |
| |
| /** |
| * Forces a particular command or operation to run. |
| */ |
| public void setForce(boolean force) { |
| this.force = force; |
| } |
| |
| /** |
| * Forces a particular command or operation to run. |
| */ |
| public boolean getForce() { |
| return force; |
| } |
| |
| /** |
| * Makes a subcommand recurse into subdirectories. Most |
| * subcommands recurse by default. |
| */ |
| public void setRecursive(Boolean recursive) { |
| this.recursive = recursive; |
| } |
| |
| /** |
| * Makes a subcommand recurse into subdirectories. Most |
| * subcommands recurse by default. |
| */ |
| public Boolean getRecursive() { |
| return recursive; |
| } |
| |
| /** |
| * Tells Subversion to get the list of files that you wish to |
| * operate on from the filename you provide instead of listing all |
| * the files on the command line. |
| */ |
| public void setTargets(File targets) { |
| this.targets = targets; |
| } |
| |
| /** |
| * Tells Subversion to get the list of files that you wish to |
| * operate on from the filename you provide instead of listing all |
| * the files on the command line. |
| */ |
| public File getTargets() { |
| return targets; |
| } |
| |
| /** |
| * This needs to be public to allow configuration |
| * of commands externally. |
| * @param arg command argument |
| */ |
| public void addSubCommandArgument(String arg) { |
| this.addSubCommandArgument(cmd, arg); |
| } |
| |
| /** |
| * This method adds a command line argument to an external subcommand. |
| * |
| * @param c command line to which one argument should be added |
| * @param arg argument to add |
| */ |
| protected void addSubCommandArgument(Commandline c, String arg) { |
| c.createArgument().setValue(arg); |
| } |
| |
| |
| /** |
| * The SVN command to execute. |
| * |
| * @param c a command as string |
| */ |
| public void setSubCommand(String c) { |
| this.subCommand = c; |
| } |
| /** |
| * accessor to a command line as string |
| * |
| * @return command line as string |
| */ |
| public String getSubCommand() { |
| return this.subCommand; |
| } |
| |
| /** |
| * If true, suppress informational messages. |
| * @param q if true, suppress informational messages |
| */ |
| public void setQuiet(boolean q) { |
| quiet = q; |
| } |
| |
| /** |
| * If true, be verbose. |
| * @param v if true, be verbose. |
| */ |
| public void setVerbose(boolean v) { |
| verbose = v; |
| } |
| |
| /** |
| * If true, report only and don't change any files. |
| * |
| * @param ne if true, report only and do not change any files. |
| */ |
| public void setDryrun(boolean ne) { |
| dryrun = ne; |
| } |
| |
| /** |
| * The file to direct standard output from the command. |
| * @param output a file to which stdout should go |
| */ |
| public void setOutput(File output) { |
| this.output = output; |
| } |
| |
| /** |
| * The file to direct standard error from the command. |
| * |
| * @param error a file to which stderr should go |
| */ |
| public void setError(File error) { |
| this.error = error; |
| } |
| |
| /** |
| * Whether to append output/error when redirecting to a file. |
| * @param value true indicated you want to append |
| */ |
| public void setAppend(boolean value) { |
| this.append = value; |
| } |
| |
| /** |
| * Stop the build process if the command exits with |
| * a return code other than 0. |
| * Defaults to false. |
| * @param failOnError stop the build process if the command exits with |
| * a return code other than 0 |
| */ |
| public void setFailOnError(boolean failOnError) { |
| this.failOnError = failOnError; |
| } |
| |
| /** |
| * Configure a commandline element for things like quiet, etc. |
| * @param c the command line which will be configured |
| * if the commandline is initially null, the function is a noop |
| * otherwise the function append to the commandline arguments concerning |
| * <ul> |
| * <li> |
| * svn |
| * </li> |
| * <li> |
| * quiet |
| * </li> |
| * <li>verbose</li> |
| * <li>dryrun</li> |
| * </ul> |
| */ |
| protected void configureCommandline(Commandline c) { |
| if (c == null) { |
| return; |
| } |
| c.setExecutable("svn"); |
| if (quiet) { |
| c.createArgument(true).setValue("--quiet"); |
| } |
| if (verbose) { |
| c.createArgument(true).setValue("--verbose"); |
| } |
| if (dryrun) { |
| c.createArgument(true).setValue("--dry-run"); |
| } |
| if (file != null) { |
| c.createArgument(true).setValue("--file"); |
| c.createArgument(true).setFile(file); |
| } |
| if (force) { |
| c.createArgument(true).setValue("--force"); |
| } |
| if (recursive != null) { |
| if (recursive.booleanValue()) { |
| c.createArgument(true).setValue("--recursive"); |
| } else { |
| c.createArgument(true).setValue("--non-recursive"); |
| } |
| } |
| if (targets != null) { |
| c.createArgument(true).setValue("--targets"); |
| c.createArgument(true).setFile(targets); |
| } |
| } |
| |
| /** |
| * remove a particular command from a vector of command lines |
| * @param c command line which should be removed |
| */ |
| protected void removeCommandline(Commandline c) { |
| vecCommandlines.removeElement(c); |
| } |
| |
| /** |
| * Adds direct command-line to execute. |
| * @param c command line to execute |
| */ |
| public void addConfiguredCommandline(Commandline c) { |
| this.addConfiguredCommandline(c, false); |
| } |
| |
| /** |
| * Configures and adds the given Commandline. |
| * @param c commandline to insert |
| * @param insertAtStart If true, c is |
| * inserted at the beginning of the vector of command lines |
| */ |
| public void addConfiguredCommandline(Commandline c, |
| boolean insertAtStart) { |
| if (c == null) { |
| return; |
| } |
| this.configureCommandline(c); |
| if (insertAtStart) { |
| vecCommandlines.insertElementAt(c, 0); |
| } else { |
| vecCommandlines.addElement(c); |
| } |
| } |
| |
| } |