1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tradefed.command; 18 19 import com.android.tradefed.config.ConfigurationException; 20 import com.android.tradefed.config.GlobalConfiguration; 21 22 import com.google.common.annotations.VisibleForTesting; 23 24 /** 25 * An alternate TradeFederation entry point that will run command specified in command 26 * line arguments and then quit. 27 * <p/> 28 * Intended for use with a debugger and other non-interactive modes of operation. 29 * <p/> 30 * Expected arguments: [commands options] (config to run) 31 */ 32 public class CommandRunner { 33 private ICommandScheduler mScheduler; 34 private ExitCode mErrorCode = ExitCode.NO_ERROR; 35 36 public CommandRunner() {} 37 38 public ExitCode getErrorCode() { 39 return mErrorCode; 40 } 41 42 /** 43 * Initialize the required global configuration. 44 */ 45 @VisibleForTesting 46 void initGlobalConfig(String[] args) throws ConfigurationException { 47 GlobalConfiguration.createGlobalConfiguration(args); 48 } 49 50 /** Get the {@link ICommandScheduler} instance from the global configuration. */ 51 @VisibleForTesting 52 ICommandScheduler getCommandScheduler() { 53 return GlobalConfiguration.getInstance().getCommandScheduler(); 54 } 55 56 /** Prints the exception stack to stderr. */ 57 @VisibleForTesting 58 void printStackTrace(Throwable e) { 59 e.printStackTrace(); 60 } 61 62 /** 63 * The main method to run the command. 64 * 65 * @param args the config name to run and its options 66 */ 67 public void run(String[] args) { 68 try { 69 initGlobalConfig(args); 70 mScheduler = getCommandScheduler(); 71 mScheduler.start(); 72 mScheduler.addCommand(args); 73 } catch (ConfigurationException e) { 74 printStackTrace(e); 75 mErrorCode = ExitCode.CONFIG_EXCEPTION; 76 } finally { 77 mScheduler.shutdownOnEmpty(); 78 } 79 try { 80 mScheduler.join(); 81 // If no error code has been raised yet, we checked the invocation error code. 82 if (ExitCode.NO_ERROR.equals(mErrorCode)) { 83 mErrorCode = mScheduler.getLastInvocationExitCode(); 84 } 85 } catch (InterruptedException e) { 86 e.printStackTrace(); 87 mErrorCode = ExitCode.THROWABLE_EXCEPTION; 88 } 89 if (!ExitCode.NO_ERROR.equals(mErrorCode) 90 && mScheduler.getLastInvocationThrowable() != null) { 91 // Print error to the stderr so that it can be recovered. 92 printStackTrace(mScheduler.getLastInvocationThrowable()); 93 } 94 } 95 96 public static void main(final String[] mainArgs) { 97 CommandRunner console = new CommandRunner(); 98 console.run(mainArgs); 99 System.exit(console.getErrorCode().getCodeValue()); 100 } 101 102 /** 103 * Error codes that are possible to exit with. 104 */ 105 public static enum ExitCode { 106 NO_ERROR(0), 107 CONFIG_EXCEPTION(1), 108 NO_BUILD(2), 109 DEVICE_UNRESPONSIVE(3), 110 DEVICE_UNAVAILABLE(4), 111 FATAL_HOST_ERROR(5), 112 THROWABLE_EXCEPTION(6); 113 114 private final int mCodeValue; 115 116 ExitCode(int codeValue) { 117 mCodeValue = codeValue; 118 } 119 120 public int getCodeValue() { 121 return mCodeValue; 122 } 123 } 124 } 125