001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.util;
019
020import java.io.IOException;
021import java.io.PrintStream;
022
023import org.apache.hadoop.classification.InterfaceAudience;
024import org.apache.hadoop.classification.InterfaceStability;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.ipc.CallerContext;
027
028/**
029 * A utility to help run {@link Tool}s.
030 * 
031 * <p><code>ToolRunner</code> can be used to run classes implementing 
032 * <code>Tool</code> interface. It works in conjunction with 
033 * {@link GenericOptionsParser} to parse the 
034 * <a href="{@docRoot}/../hadoop-project-dist/hadoop-common/CommandsManual.html#Generic_Options">
035 * generic hadoop command line arguments</a> and modifies the 
036 * <code>Configuration</code> of the <code>Tool</code>. The 
037 * application-specific options are passed along without being modified.
038 * </p>
039 * 
040 * @see Tool
041 * @see GenericOptionsParser
042 */
043@InterfaceAudience.Public
044@InterfaceStability.Stable
045public class ToolRunner {
046 
047  /**
048   * Runs the given <code>Tool</code> by {@link Tool#run(String[])}, after 
049   * parsing with the given generic arguments. Uses the given 
050   * <code>Configuration</code>, or builds one if null.
051   * 
052   * Sets the <code>Tool</code>'s configuration with the possibly modified 
053   * version of the <code>conf</code>.  
054   * 
055   * @param conf <code>Configuration</code> for the <code>Tool</code>.
056   * @param tool <code>Tool</code> to run.
057   * @param args command-line arguments to the tool.
058   * @return exit code of the {@link Tool#run(String[])} method.
059   */
060  public static int run(Configuration conf, Tool tool, String[] args) 
061    throws Exception{
062    if (CallerContext.getCurrent() == null) {
063      CallerContext ctx = new CallerContext.Builder("CLI").build();
064      CallerContext.setCurrent(ctx);
065    }
066    
067    if(conf == null) {
068      conf = new Configuration();
069    }
070    GenericOptionsParser parser = new GenericOptionsParser(conf, args);
071    //set the configuration back, so that Tool can configure itself
072    tool.setConf(conf);
073    
074    //get the args w/o generic hadoop args
075    String[] toolArgs = parser.getRemainingArgs();
076    return tool.run(toolArgs);
077  }
078  
079  /**
080   * Runs the <code>Tool</code> with its <code>Configuration</code>.
081   * 
082   * Equivalent to <code>run(tool.getConf(), tool, args)</code>.
083   * 
084   * @param tool <code>Tool</code> to run.
085   * @param args command-line arguments to the tool.
086   * @return exit code of the {@link Tool#run(String[])} method.
087   */
088  public static int run(Tool tool, String[] args) 
089    throws Exception{
090    return run(tool.getConf(), tool, args);
091  }
092  
093  /**
094   * Prints generic command-line argurments and usage information.
095   * 
096   *  @param out stream to write usage information to.
097   */
098  public static void printGenericCommandUsage(PrintStream out) {
099    GenericOptionsParser.printGenericCommandUsage(out);
100  }
101  
102  
103  /**
104   * Print out a prompt to the user, and return true if the user
105   * responds with "y" or "yes". (case insensitive)
106   */
107  public static boolean confirmPrompt(String prompt) throws IOException {
108    while (true) {
109      System.err.print(prompt + " (Y or N) ");
110      StringBuilder responseBuilder = new StringBuilder();
111      while (true) {
112        int c = System.in.read();
113        if (c == -1 || c == '\r' || c == '\n') {
114          break;
115        }
116        responseBuilder.append((char)c);
117      }
118  
119      String response = responseBuilder.toString();
120      if (response.equalsIgnoreCase("y") ||
121          response.equalsIgnoreCase("yes")) {
122        return true;
123      } else if (response.equalsIgnoreCase("n") ||
124          response.equalsIgnoreCase("no")) {
125        return false;
126      }
127      System.err.println("Invalid input: " + response);
128      // else ask them again
129    }
130  }
131}