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     */
018    package org.apache.hadoop.util;
019    
020    import java.io.IOException;
021    import java.io.PrintStream;
022    
023    import org.apache.hadoop.classification.InterfaceAudience;
024    import org.apache.hadoop.classification.InterfaceStability;
025    import org.apache.hadoop.conf.Configuration;
026    
027    /**
028     * A utility to help run {@link Tool}s.
029     * 
030     * <p><code>ToolRunner</code> can be used to run classes implementing 
031     * <code>Tool</code> interface. It works in conjunction with 
032     * {@link GenericOptionsParser} to parse the 
033     * <a href="{@docRoot}/org/apache/hadoop/util/GenericOptionsParser.html#GenericOptions">
034     * generic hadoop command line arguments</a> and modifies the 
035     * <code>Configuration</code> of the <code>Tool</code>. The 
036     * application-specific options are passed along without being modified.
037     * </p>
038     * 
039     * @see Tool
040     * @see GenericOptionsParser
041     */
042    @InterfaceAudience.Public
043    @InterfaceStability.Stable
044    public class ToolRunner {
045     
046      /**
047       * Runs the given <code>Tool</code> by {@link Tool#run(String[])}, after 
048       * parsing with the given generic arguments. Uses the given 
049       * <code>Configuration</code>, or builds one if null.
050       * 
051       * Sets the <code>Tool</code>'s configuration with the possibly modified 
052       * version of the <code>conf</code>.  
053       * 
054       * @param conf <code>Configuration</code> for the <code>Tool</code>.
055       * @param tool <code>Tool</code> to run.
056       * @param args command-line arguments to the tool.
057       * @return exit code of the {@link Tool#run(String[])} method.
058       */
059      public static int run(Configuration conf, Tool tool, String[] args) 
060        throws Exception{
061        if(conf == null) {
062          conf = new Configuration();
063        }
064        GenericOptionsParser parser = new GenericOptionsParser(conf, args);
065        //set the configuration back, so that Tool can configure itself
066        tool.setConf(conf);
067        
068        //get the args w/o generic hadoop args
069        String[] toolArgs = parser.getRemainingArgs();
070        return tool.run(toolArgs);
071      }
072      
073      /**
074       * Runs the <code>Tool</code> with its <code>Configuration</code>.
075       * 
076       * Equivalent to <code>run(tool.getConf(), tool, args)</code>.
077       * 
078       * @param tool <code>Tool</code> to run.
079       * @param args command-line arguments to the tool.
080       * @return exit code of the {@link Tool#run(String[])} method.
081       */
082      public static int run(Tool tool, String[] args) 
083        throws Exception{
084        return run(tool.getConf(), tool, args);
085      }
086      
087      /**
088       * Prints generic command-line argurments and usage information.
089       * 
090       *  @param out stream to write usage information to.
091       */
092      public static void printGenericCommandUsage(PrintStream out) {
093        GenericOptionsParser.printGenericCommandUsage(out);
094      }
095      
096      
097      /**
098       * Print out a prompt to the user, and return true if the user
099       * responds with "y" or "yes". (case insensitive)
100       */
101      public static boolean confirmPrompt(String prompt) throws IOException {
102        while (true) {
103          System.err.print(prompt + " (Y or N) ");
104          StringBuilder responseBuilder = new StringBuilder();
105          while (true) {
106            int c = System.in.read();
107            if (c == -1 || c == '\r' || c == '\n') {
108              break;
109            }
110            responseBuilder.append((char)c);
111          }
112      
113          String response = responseBuilder.toString();
114          if (response.equalsIgnoreCase("y") ||
115              response.equalsIgnoreCase("yes")) {
116            return true;
117          } else if (response.equalsIgnoreCase("n") ||
118              response.equalsIgnoreCase("no")) {
119            return false;
120          }
121          System.err.println("Invalid input: " + response);
122          // else ask them again
123        }
124      }
125    }