/**
** Copyright (C) SAS Institute, All rights reserved.
** General Public License: http://www.opensource.org/licenses/gpl-license.php
**/
package org.safs.android.auto.lib;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public abstract class ConsoleTool {
protected Console console = null;
/**
* contains possible sub-directories from tool-home where the tool stays<br>
* For example, bin, tools, platform-tools etc.
*/
protected final List<String> binDirectories = new ArrayList<String>();
/**
* The absolute path of the tool's home
*/
private String toolHome = null;
public ConsoleTool(){
console = Console.get();
modifyBinDirectories();
}
public List<String> getBinDirectories() {
return binDirectories;
}
/**
* This method will modify the {@link #binDirectories} according to tool itself.<br>
* @see binDirectories
*/
protected abstract void modifyBinDirectories();
public static String getOsFamilyName(){
return Console.getOsFamilyName();
}
public static boolean isWindowsOS(){
return Console.isWindowsOS();
}
public static boolean isUnixOS(){
return Console.isUnixOS();
}
public static boolean isMacOS(){
return Console.isMacOS();
}
/**
* Try to find the location of the executable tools in the sdk's home path.
* It will try to look the tool in some sub directories, such as bin, tools
* If still not found, throw the IllegalStateException.
*
* @param tool name like "adb.exe", "batch.bat" or "script.sh" etc...
* @return String absolute path to the tool or throws the exception
* @throws IllegalStateException if tool cannot be found.
*/
protected String locateTool(String tool) {
String path = null;
String toolHome = getToolHome();
File directory = null;
for(String bin: binDirectories){
directory = new File(toolHome, bin);
if(directory==null || !directory.isDirectory()){
continue;
}
path = searchFile(directory, tool, needSearchRecursively(bin));
if(path!=null){
//we found the tool, just get out of the loop
break;
}
}
if (path == null) {
throw new IllegalStateException("Can't find " + tool + " inside the sdk at " + toolHome);
}
return path;
}
/**
* Try to find a file matching 'filename' within directory.
*
* @param directory File, the directory in which to search file
* @param filename String, the filename to match
* @param recusive boolean, if we need to search files in sub-directories
* @return String, the absolute filename or null if not found.
* @see #locateTool(String)
*/
protected String searchFile(File directory, String filename, boolean recusive){
String path = null;
for (File file : directory.listFiles()) {
if(recusive && file.isDirectory()){
path = searchFile(file, filename, recusive);
if(path!=null) return path;
}
if (!file.getName().equalsIgnoreCase(filename)) continue;
if(!file.canExecute()) continue;
path = file.getAbsolutePath();
break;
}
return path;
}
/**
* @param directoryName String, the directory to be searched
* @return boolean, true if we need to search in the sub-directories
* @see #locateTool(String)
*/
protected boolean needSearchRecursively(String directoryName){
return false;
}
/**
* Only you are sure about the tool's home, you can set it.<br>
* Because if you set it, {@link #getToolHome()} will not try to get the tool's home<br>
* from "JVM properties" or "System environment variables"<br>
* This method will verify if the toolHome exists and is a directory. If not, it will<br>
* throw out IllegalStateException.
*
* @param toolHome
* @throws IllegalStateException
*
* @see #getToolHome()
*/
public void setToolHome(String toolHome) {
if(toolHome==null){
throw new IllegalStateException("toolHome is null, can't set it.");
}
File toolHomeFile = new File(toolHome);
if (!toolHomeFile.exists()) {
throw new IllegalStateException("" + toolHome + " doesn't exist.");
}
if (!toolHomeFile.isDirectory()) {
throw new IllegalStateException("" + toolHome + " isn't a directory.");
}
this.toolHome = toolHome;
}
/**
* This method will firstly try to return the field {@link #toolHome}<br>
* If it is null, it will try to get the toolHome from properties {@link #getToolHomeProperties()}<br>
* If still not found, it will try to get the toolHome from environments {@link #getToolHomeEnvs()}<br>
* If still not found, it will throw out IllegalStateException.<br>
* If the toolHome if found, it will be set to field {@link #toolHome}.<br>
*
* @return The tool home where (or sub-directory) the tools' executable can be found.
* @throws IllegalStateException
*
* @see #setToolHome(String)
*/
public String getToolHome() {
String toolHome = this.toolHome;
if(toolHome!=null){
return toolHome;
}else{
for(String property: getToolHomeProperties()){
toolHome = System.getProperty(property);
if(toolHome!=null) break;
}
}
if (toolHome == null){
for(String env: getToolHomeEnvs()){
toolHome = System.getenv(env);
if(toolHome!=null) break;
}
}
if (toolHome == null) {
String errorMsg = "Can't find the tool sdk home. ";
if(getToolHomeProperties().size()>0){
errorMsg += "Set the " + getListString(getToolHomeProperties()) + " system property to your sdk root.";
}
if(getToolHomeEnvs().size()>0){
errorMsg += "Set the " + getListString(getToolHomeEnvs()) + " environment variables to your sdk root.";
}
throw new IllegalStateException(errorMsg);
}
setToolHome(toolHome);
return toolHome;
}
/**
* Subclass should override this method to provide its own system properties.<br>
* @return A list of 'system property name', where the 'tool home' may be stored.
*/
protected List<String> getToolHomeProperties(){
return new ArrayList<String>();
}
/**
* Subclass should override this method to provide its own environment variables.<br>
* @return A list of 'environment variable name', where the 'tool home' may be stored.
*/
protected List<String> getToolHomeEnvs(){
return new ArrayList<String>();
}
/**
* Convert a list of string to a comma-separated string
* @param list List of String
* @return a comma-separated string
*/
private String getListString(List<String> list){
String string = "";
for(String value: list){
string += value+", ";
}
//remove the last comma
int index = string.lastIndexOf(",");
if(index>-1){
string = string.substring(0, index);
}
return string;
}
public Process2 exec(String tool, String... args) throws IOException {
return exec(tool, Console.asList(args));
}
public Process2 exec(String tool, List<String> args) throws IOException {
return console.start(locateTool(tool), args);
}
public Process2 exec(File workingDirectory, String... binaryAndArgs) throws IOException {
return exec(workingDirectory, Console.asList(binaryAndArgs));
}
public Process2 exec(File workingDirectory, List<String> binaryAndArgs) throws IOException {
if(binaryAndArgs.size()>0){
String tool = locateTool(binaryAndArgs.get(0));
binaryAndArgs.set(0, tool);
}
return console.start(workingDirectory, binaryAndArgs);
}
public Process2 batch(String tool, String... args) throws IOException {
List<String> batchAndArgs = Console.asList(args);
batchAndArgs.add(0, tool);
return batch(null, batchAndArgs);
}
public Process2 batch(File workingDirectory, String... batchAndArgs) throws IOException{
return batch(workingDirectory, Console.asList(batchAndArgs));
}
public Process2 batch(File workingDirectory, List<String> batchAndArgs) throws IOException{
if(batchAndArgs.size()>0){
String tool = locateTool(batchAndArgs.get(0));
batchAndArgs.set(0, tool);
}
return console.batch(workingDirectory, batchAndArgs);
}
}