/** * Copyright 2013 Cloudera Inc. * * Licensed 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.kitesdk.cli; import com.beust.jcommander.JCommander; import com.beust.jcommander.MissingCommandException; import com.beust.jcommander.Parameter; import com.beust.jcommander.ParameterException; import com.beust.jcommander.Parameters; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; import com.google.common.io.Closeables; import java.io.InputStream; import java.util.Properties; import java.util.Set; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configurable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import org.apache.log4j.Level; import org.apache.log4j.PropertyConfigurator; import org.kitesdk.cli.commands.CSVImportCommand; import org.kitesdk.cli.commands.CSVSchemaCommand; import org.kitesdk.cli.commands.CompactCommand; import org.kitesdk.cli.commands.CopyCommand; import org.kitesdk.cli.commands.CreateColumnMappingCommand; import org.kitesdk.cli.commands.CreateDatasetCommand; import org.kitesdk.cli.commands.CreatePartitionStrategyCommand; import org.kitesdk.cli.commands.DeleteCommand; import org.kitesdk.cli.commands.FlumeConfigCommand; import org.kitesdk.cli.commands.InfoCommand; import org.kitesdk.cli.commands.InputFormatImportCommand; import org.kitesdk.cli.commands.JSONImportCommand; import org.kitesdk.cli.commands.JSONSchemaCommand; import org.kitesdk.cli.commands.ListCommand; import org.kitesdk.cli.commands.Log4jConfigCommand; import org.kitesdk.cli.commands.ObjectSchemaCommand; import org.kitesdk.cli.commands.SchemaCommand; import org.kitesdk.cli.commands.ShowRecordsCommand; import org.kitesdk.cli.commands.TarImportCommand; import org.kitesdk.cli.commands.TransformCommand; import org.kitesdk.cli.commands.UpdateDatasetCommand; import org.kitesdk.data.DatasetIOException; import org.kitesdk.data.DatasetNotFoundException; import org.kitesdk.data.ValidationException; import org.kitesdk.data.spi.DefaultConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Parameters(commandDescription = "Kite dataset management utility") public class Main extends Configured implements Tool { @Parameter(names = {"-v", "--verbose", "--debug"}, description = "Print extra debugging information") private boolean debug = false; @Parameter(names = {"--version"}, description = "Print Kite version and exit") private boolean printVersion = false; @VisibleForTesting @Parameter(names="--dollar-zero", description="A way for the runtime path to be passed in", hidden=true) String programName = DEFAULT_PROGRAM_NAME; @VisibleForTesting static final String DEFAULT_PROGRAM_NAME = "kite-dataset"; private static Set<String> HELP_ARGS = ImmutableSet.of("-h", "-help", "--help", "help"); private final Logger console; private final Help help; @VisibleForTesting final JCommander jc; Main(Logger console) { this.console = console; this.jc = new JCommander(this); this.help = new Help(jc, console); jc.setProgramName(DEFAULT_PROGRAM_NAME); jc.addCommand("help", help, "-h", "-help", "--help"); jc.addCommand("list", new ListCommand(console)); jc.addCommand("create", new CreateDatasetCommand(console)); jc.addCommand("copy", new CopyCommand(console)); jc.addCommand("transform", new TransformCommand(console)); jc.addCommand("compact", new CompactCommand(console)); jc.addCommand("update", new UpdateDatasetCommand(console)); jc.addCommand("delete", new DeleteCommand(console)); jc.addCommand("schema", new SchemaCommand(console)); jc.addCommand("info", new InfoCommand(console)); jc.addCommand("show", new ShowRecordsCommand(console)); jc.addCommand("obj-schema", new ObjectSchemaCommand(console)); jc.addCommand("inputformat-import", new InputFormatImportCommand(console)); jc.addCommand("csv-schema", new CSVSchemaCommand(console)); jc.addCommand("csv-import", new CSVImportCommand(console)); jc.addCommand("json-schema", new JSONSchemaCommand(console)); jc.addCommand("json-import", new JSONImportCommand(console)); jc.addCommand("partition-config", new CreatePartitionStrategyCommand(console)); jc.addCommand("mapping-config", new CreateColumnMappingCommand(console)); jc.addCommand("log4j-config", new Log4jConfigCommand(console)); jc.addCommand("flume-config", new FlumeConfigCommand(console)); jc.addCommand("tar-import", new TarImportCommand(console)); } @Override public int run(String[] args) throws Exception { if (getConf() != null) { DefaultConfiguration.set(getConf()); } try { jc.parse(args); } catch (MissingCommandException e) { console.error(e.getMessage()); return 1; } catch (ParameterException e) { help.setProgramName(programName); String cmd = jc.getParsedCommand(); if (args.length == 1) { // i.e., just the command (missing required arguments) help.helpCommands.add(cmd); help.run(); return 1; } else { // check for variants like 'cmd --help' etc. for (String arg : args) { if (HELP_ARGS.contains(arg)) { help.helpCommands.add(cmd); help.run(); return 0; } } } console.error(e.getMessage()); return 1; } help.setProgramName(programName); if (printVersion) { console.info("Kite version \"{}\"", getVersion()); return 0; } // configure log4j if (debug) { org.apache.log4j.Logger console = org.apache.log4j.Logger.getLogger(Main.class); console.setLevel(Level.DEBUG); } String parsed = jc.getParsedCommand(); if (parsed == null) { help.run(); return 1; } else if ("help".equals(parsed)) { return help.run(); } Command command = (Command) jc.getCommands().get(parsed).getObjects().get(0); if (command == null) { help.run(); return 1; } try { if (command instanceof Configurable) { ((Configurable) command).setConf(getConf()); } return command.run(); } catch (IllegalArgumentException e) { if (debug) { console.error("Argument error", e); } else { console.error("Argument error: {}", e.getMessage()); } return 1; } catch (IllegalStateException e) { if (debug) { console.error("State error", e); } else { console.error("State error: {}", e.getMessage()); } return 1; } catch (ValidationException e) { if (debug) { console.error("Validation error", e); } else { console.error("Validation error: {}", e.getMessage()); } return 1; } catch (DatasetNotFoundException e) { if (debug) { console.error("Cannot find dataset", e); } else { // the error message already contains "No such dataset: <name>" console.error(e.getMessage()); } return 1; } catch (DatasetIOException e) { if (debug) { console.error("IO error", e); } else { console.error("IO error: {}", e.getMessage()); } return 1; } catch (Exception e) { if (debug) { console.error("Unknown error", e); } else { console.error("Unknown error: {}", e.getMessage()); } return 1; } } @SuppressWarnings({"BroadCatchBlock", "TooBroadCatch"}) private String getVersion() { String location = "/META-INF/maven/org.kitesdk/kite-tools/pom.properties"; String version = "unknown"; InputStream pomPropertiesStream = null; try { Properties pomProperties = new Properties(); pomPropertiesStream = Main.class.getResourceAsStream(location); pomProperties.load(pomPropertiesStream); version = pomProperties.getProperty("version"); } catch (Exception ex) { if (debug) { console.warn("Unable to determine version from the {} file", location); console.warn("Exception:", ex); } else { console.warn("Unable to determine version from the {} file: {}", location, ex.getMessage()); } } finally { Closeables.closeQuietly(pomPropertiesStream); } return version; } public static void main(String[] args) throws Exception { // reconfigure logging with the kite CLI configuration PropertyConfigurator.configure( Main.class.getResource("/kite-cli-logging.properties")); Logger console = LoggerFactory.getLogger(Main.class); // use Log4j for any libraries using commons-logging LogFactory.getFactory().setAttribute( "org.apache.commons.logging.Log", "org.apache.commons.logging.impl.Log4JLogger"); int rc = ToolRunner.run(new HiveConf(), new Main(console), args); System.exit(rc); } }