| /** |
| * 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.hadoop.ant; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.OutputStream; |
| import java.io.PrintStream; |
| |
| import java.util.LinkedList; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.FsShell; |
| |
| import org.apache.tools.ant.AntClassLoader; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Task; |
| import org.apache.hadoop.util.ToolRunner; |
| |
| import org.apache.hadoop.classification.InterfaceAudience; |
| import org.apache.hadoop.hdfs.HdfsConfiguration; |
| |
| /** |
| * {@link org.apache.hadoop.fs.FsShell FsShell} wrapper for ant Task. |
| */ |
| @InterfaceAudience.Private |
| public class DfsTask extends Task { |
| |
| /** |
| * Default sink for {@link java.lang.System.out System.out} |
| * and {@link java.lang.System.err System.err}. |
| */ |
| private static final OutputStream nullOut = new OutputStream() { |
| public void write(int b) { /* ignore */ } |
| public String toString() { return ""; } |
| }; |
| private static final FsShell shell = new FsShell(); |
| |
| protected AntClassLoader confloader; |
| protected OutputStream out = nullOut; |
| protected OutputStream err = nullOut; |
| |
| // set by ant |
| protected String cmd; |
| protected final LinkedList<String> argv = new LinkedList<String>(); |
| protected String outprop; |
| protected String errprop; |
| protected boolean failonerror = true; |
| |
| // saved ant context |
| private PrintStream antOut; |
| private PrintStream antErr; |
| |
| /** |
| * Sets the command to run in {@link org.apache.hadoop.fs.FsShell FsShell}. |
| * @param cmd A valid command to FsShell, sans "-". |
| */ |
| public void setCmd(String cmd) { |
| this.cmd = "-" + cmd.trim(); |
| } |
| |
| /** |
| * Sets the argument list from a String of comma-separated values. |
| * @param args A String of comma-separated arguments to FsShell. |
| */ |
| public void setArgs(String args) { |
| for (String s : args.trim().split("\\s*,\\s*")) |
| argv.add(s); |
| } |
| |
| /** |
| * Sets the property into which System.out will be written. |
| * @param outprop The name of the property into which System.out is written. |
| * If the property is defined before this task is executed, it will not be updated. |
| */ |
| public void setOut(String outprop) { |
| this.outprop = outprop; |
| out = new ByteArrayOutputStream(); |
| if (outprop.equals(errprop)) |
| err = out; |
| } |
| |
| /** |
| * Sets the property into which System.err will be written. If this property |
| * has the same name as the property for System.out, the two will be interlaced. |
| * @param errprop The name of the property into which System.err is written. |
| * If the property is defined before this task is executed, it will not be updated. |
| */ |
| public void setErr(String errprop) { |
| this.errprop = errprop; |
| err = (errprop.equals(outprop)) ? err = out : new ByteArrayOutputStream(); |
| } |
| |
| /** |
| * Sets the path for the parent-last ClassLoader, intended to be used for |
| * {@link org.apache.hadoop.conf.Configuration Configuration}. |
| * @param confpath The path to search for resources, classes, etc. before |
| * parent ClassLoaders. |
| */ |
| public void setConf(String confpath) { |
| confloader = new AntClassLoader(getClass().getClassLoader(), false); |
| confloader.setProject(getProject()); |
| if (null != confpath) |
| confloader.addPathElement(confpath); |
| } |
| |
| /** |
| * Sets a property controlling whether or not a |
| * {@link org.apache.tools.ant.BuildException BuildException} will be thrown |
| * if the command returns a value less than zero or throws an exception. |
| * @param failonerror If true, throw a BuildException on error. |
| */ |
| public void setFailonerror(boolean failonerror) { |
| this.failonerror = failonerror; |
| } |
| |
| /** |
| * Save the current values of System.out, System.err and configure output |
| * streams for FsShell. |
| */ |
| protected void pushContext() { |
| antOut = System.out; |
| antErr = System.err; |
| System.setOut(new PrintStream(out)); |
| System.setErr(out == err ? System.out : new PrintStream(err)); |
| } |
| |
| /** |
| * Create the appropriate output properties with their respective output, |
| * restore System.out, System.err and release any resources from created |
| * ClassLoaders to aid garbage collection. |
| */ |
| protected void popContext() { |
| // write output to property, if applicable |
| if (outprop != null && !System.out.checkError()) |
| getProject().setNewProperty(outprop, out.toString()); |
| if (out != err && errprop != null && !System.err.checkError()) |
| getProject().setNewProperty(errprop, err.toString()); |
| |
| System.setErr(antErr); |
| System.setOut(antOut); |
| confloader.cleanup(); |
| confloader.setParent(null); |
| } |
| |
| // in case DfsTask is overridden |
| protected int postCmd(int exit_code) { |
| if ("-test".equals(cmd) && exit_code != 0) |
| outprop = null; |
| return exit_code; |
| } |
| |
| /** |
| * Invoke {@link org.apache.hadoop.fs.FsShell#doMain FsShell.doMain} after a |
| * few cursory checks of the configuration. |
| */ |
| public void execute() throws BuildException { |
| if (null == cmd) |
| throw new BuildException("Missing command (cmd) argument"); |
| argv.add(0, cmd); |
| |
| if (null == confloader) { |
| setConf(getProject().getProperty("hadoop.conf.dir")); |
| } |
| |
| int exit_code = 0; |
| try { |
| pushContext(); |
| |
| Configuration conf = new HdfsConfiguration(); |
| conf.setClassLoader(confloader); |
| exit_code = ToolRunner.run(conf, shell, |
| argv.toArray(new String[argv.size()])); |
| exit_code = postCmd(exit_code); |
| |
| if (0 > exit_code) { |
| StringBuilder msg = new StringBuilder(); |
| for (String s : argv) |
| msg.append(s + " "); |
| msg.append("failed: " + exit_code); |
| throw new Exception(msg.toString()); |
| } |
| } catch (Exception e) { |
| if (failonerror) |
| throw new BuildException(e); |
| } finally { |
| popContext(); |
| } |
| } |
| } |