|
@@ -0,0 +1,210 @@
|
|
|
+/**
|
|
|
+ * 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.security.AccessController;
|
|
|
+import java.security.PrivilegedAction;
|
|
|
+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 = AccessController.doPrivileged(
|
|
|
+ new PrivilegedAction<AntClassLoader>() {
|
|
|
+ @Override
|
|
|
+ public AntClassLoader run() {
|
|
|
+ return 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();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|