/*
* Copyright (c) 2010-2016, Sikuli.org, sikulix.com
* Released under the MIT License.
*
*/
package org.sikuli.script;
import org.sikuli.basics.Debug;
import org.sikuli.basics.FileManager;
import org.sikuli.basics.Settings;
import org.sikuli.util.JythonHelper;
import org.sikuli.util.LinuxSupport;
import org.sikuli.util.SysJNA;
import java.awt.*;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.util.*;
import java.util.List;
import java.util.prefs.Preferences;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* INTERNAL USE --- NOT official API<br>
* not as is in version 2
*
* Intended to concentrate all, that is needed at startup of sikulix or sikulixapi and may be at runtime by SikuliX or
* any caller
*/
public class RunTime {
public static File scriptProject = null;
public static URL uScriptProject = null;
public static boolean shouldRunServer = false;
private static boolean isTerminating = false;
public static void resetProject() {
scriptProject = null;
uScriptProject = null;
}
public static String appDataMsg = "";
public static void pause(int time) {
try {
Thread.sleep(time * 1000);
} catch (InterruptedException ex) {
}
}
public static void pause(float time) {
try {
Thread.sleep((int) (time * 1000));
} catch (InterruptedException ex) {
}
}
protected void abortScripting(String msg1, String msg2) {
Thread current = Thread.currentThread();
String where = "unknown";
if (Region.runTime.isJythonReady) {
where = JythonHelper.get().getCurrentLine();
}
log(-1, msg1 + " %s", where);
log(-1, msg2);
current.interrupt();
current.stop();
}
//<editor-fold defaultstate="collapsed" desc="logging">
private final String me = "RunTime%s: ";
private int lvl = 3;
private int minLvl = lvl;
private static String preLogMessages = "";
public final static String runCmdError = "*****error*****";
public static String NL = "\n";
public boolean runningInteractive = false;
public boolean runningTests = false;
public String interactiveRunner;
public File fLibsProvided;
public File fLibsLocal;
public boolean useLibsProvided = false;
private String lastResult = "";
public boolean shouldCleanDownloads = false;
public boolean isJythonReady = false;
private boolean shouldExport = false;
private void log(int level, String message, Object... args) {
Debug.logx(level, String.format(me, runType) + message, args);
}
private void logp(String message, Object... args) {
Debug.logx(-3, message, args);
}
private void logp(int level, String message, Object... args) {
if (level <= Debug.getDebugLevel()) {
logp(message, args);
}
}
public void terminate(int retval, String message, Object... args) {
log(-1, " *** terminating: " + message, args);
System.exit(retval);
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="instance">
/**
* INTERNAL USE
*/
private RunTime() {
}
public static synchronized RunTime get(Type typ) {
return get(typ, null);
}
/**
* INTERNAL USE to initialize the runtime environment for SikuliX<br>
* for public use: use RunTime.get() to get the existing instance
*
* @param typ IDE or API
* @return the RunTime singleton instance
*/
public static synchronized RunTime get(Type typ, String[] clArgs) {
if (runTime == null) {
runTime = new RunTime();
int debugLevel = 0;
if (null != clArgs) {
debugLevel = checkArgs(clArgs, typ);
if (Type.IDE.equals(typ)) {
if (debugLevel == -1) {
Debug.on(3);
Debug.log(3, "RunTime: option -d detected --- log goes to SikulixLog.txt");
Debug.setLogFile("");
Settings.LogTime = true;
System.setProperty("sikuli.console", "false");
} else if (debugLevel == 999) {
runTime.runningScripts = true;
} else if (debugLevel == -3) {
//if (Type.IDE.equals(typ) && "runserver".equals(opt)) {
shouldRunServer = true;
}
}
}
if (Type.API.equals(typ)) {
Debug.init();
}
//<editor-fold defaultstate="collapsed" desc="versions">
String vJava = System.getProperty("java.runtime.version");
String vVM = System.getProperty("java.vm.version");
String vClass = System.getProperty("java.class.version");
String vSysArch = System.getProperty("sikuli.arch");
if (null == vSysArch) {
vSysArch = System.getProperty("os.arch");
} else {
runTime.log(runTime.lvl, "SystemProperty given: sikuli.arch=%s", vSysArch);
}
if (vSysArch != null) {
if (vSysArch.contains("64")) {
runTime.javaArch = 64;
}
} else {
runTime.log(runTime.lvl, "Java arch (32 or 64 Bit) not detected nor given - using %d Bit", runTime.javaArch);
}
try {
runTime.javaVersion = Integer.parseInt(vJava.substring(2, 3));
runTime.javaShow = String.format("java %d-%d version %s vm %s class %s arch %s",
runTime.javaVersion, runTime.javaArch, vJava, vVM, vClass, vSysArch);
} catch (Exception ex) {
runTime.log(-1, "Java version not detected (using 7): %s", vJava);
runTime.javaVersion = 7;
runTime.javaShow = String.format("java ?7?-%d version %s vm %s class %s arch %s",
runTime.javaArch, vJava, vVM, vClass, vSysArch);
runTime.logp(runTime.javaShow);
runTime.dumpSysProps();
}
if (Debug.getDebugLevel() > runTime.minLvl) {
runTime.dumpSysProps();
}
if (!runTime.isJava7()) {
runTime.terminate(-1, "Java version must be 1.7 or later!");
}
runTime.osVersion = runTime.osVersionSysProp;
String os = runTime.osNameSysProp.toLowerCase();
if (os.startsWith("windows")) {
runTime.runningOn = theSystem.WIN;
runTime.sysName = "windows";
runTime.osName = "Windows";
runTime.runningWindows = true;
runTime.NL = "\r\n";
} else if (os.startsWith("mac")) {
runTime.runningOn = theSystem.MAC;
runTime.sysName = "mac";
runTime.osName = "Mac OSX";
runTime.runningMac = true;
} else if (os.startsWith("linux")) {
runTime.runningOn = theSystem.LUX;
runTime.sysName = "linux";
runTime.osName = "Linux";
runTime.runningLinux = true;
String result = runTime.runcmd("lsb_release -i -r -s");
if (result.contains("*** error ***")) {
runTime.log(-1, "command returns error: lsb_release -i -r -s\n%s", result);
} else {
runTime.linuxDistro = result.replaceAll("\n", " ").trim();
}
} else {
// Presume Unix -- pretend to be Linux
runTime.runningOn = theSystem.LUX;
runTime.sysName = os;
runTime.osName = runTime.osNameSysProp;
runTime.runningLinux = true;
runTime.linuxDistro = runTime.osNameSysProp;
}
runTime.fpJarLibs += runTime.sysName + "/libs" + runTime.javaArch;
runTime.fpSysLibs = runTime.fpJarLibs.substring(1);
String aFolder = System.getProperty("user.home");
if (aFolder == null || aFolder.isEmpty() || !(runTime.fUserDir = new File(aFolder)).exists()) {
runTime.terminate(-1, "JavaSystemProperty::user.home not valid");
}
aFolder = System.getProperty("user.dir");
if (aFolder == null || aFolder.isEmpty() || !(runTime.fWorkDir = new File(aFolder)).exists()) {
runTime.terminate(-1, "JavaSystemProperty::user.dir not valid");
}
runTime.fSikulixAppPath = new File("SikulixAppDataNotAvailable");
if (runTime.runningWindows) {
appDataMsg = "init: Windows: %APPDATA% not valid (null or empty) or is not accessible:\n%s";
String tmpdir = System.getenv("APPDATA");
if (tmpdir != null && !tmpdir.isEmpty()) {
runTime.fAppPath = new File(tmpdir);
runTime.fSikulixAppPath = new File(runTime.fAppPath, "Sikulix");
}
} else if (runTime.runningMac) {
appDataMsg = "init: Mac: SikulxAppData does not exist or is not accessible:\n%s";
runTime.fAppPath = new File(runTime.fUserDir, "Library/Application Support");
runTime.fSikulixAppPath = new File(runTime.fAppPath, "Sikulix");
} else if (runTime.runningLinux) {
runTime.fAppPath = runTime.fUserDir;
runTime.fSikulixAppPath = new File(runTime.fAppPath, ".Sikulix");
appDataMsg = "init: Linux: SikulxAppData does not exist or is not accessible:\n%s";
}
runTime.fSikulixStore = new File(runTime.fSikulixAppPath, "SikulixStore");
runTime.fSikulixStore.mkdirs();
//</editor-fold>
debugLevelSaved = Debug.getDebugLevel();
debugLogfileSaved = Debug.logfile;
File fDebug = new File(runTime.fSikulixStore, "SikulixDebug.txt");
if (fDebug.exists()) {
if (Debug.getDebugLevel() == 0) {
Debug.setDebugLevel(3);
}
Debug.setLogFile(fDebug.getAbsolutePath());
if (Type.IDE.equals(typ)) {
System.setProperty("sikuli.console", "false");
}
runTime.logp("auto-debugging with level %d into:\n%s", Debug.getDebugLevel(), fDebug);
}
runTime.fTestFolder = new File(runTime.fUserDir, "SikulixTest");
runTime.fTestFile = new File(runTime.fTestFolder, "SikulixTest.txt");
runTime.loadOptions(typ);
int dl = runTime.getOptionNumber("Debug.level");
if (dl > 0 && Debug.getDebugLevel() < 2) {
Debug.setDebugLevel(dl);
}
if (Debug.getDebugLevel() == 2) {
runTime.dumpOptions();
}
if (Type.SETUP.equals(typ) && debugLevel != -2) {
Debug.setDebugLevel(3);
}
Settings.init(); // force Settings initialization
runTime.initSikulixOptions();
runTime.init(typ);
if (Type.IDE.equals(typ)) {
runTime.initIDEbefore();
runTime.initAPI();
runTime.initIDEafter();
} else {
runTime.initAPI();
if (Type.SETUP.equals(typ)) {
runTime.initSetup();
}
}
}
if (testingWinApp && !runTime.runningWindows) {
runTime.terminate(1, "***** for testing winapp: not running on Windows");
}
return runTime;
}
/**
* get the initialized RunTime singleton instance
*
* @return
*/
public static synchronized RunTime get() {
if (runTime == null) {
return get(Type.API);
}
return runTime;
}
/**
* INTERNAL USE get a new initialized RunTime singleton instance
*
* @return
*/
public static synchronized RunTime reset(Type typ) {
if (runTime != null) {
preLogMessages += "RunTime: resetting RunTime instance;";
if (Sikulix.testNumber == 1) {
Debug.setDebugLevel(debugLevelSaved);
}
Debug.setLogFile(debugLogfileSaved);
runTime = null;
}
return get(typ);
}
/**
* INTERNAL USE get a new initialized RunTime singleton instance
*
* @return
*/
public static synchronized RunTime reset() {
return reset(Type.API);
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="variables">
public enum Type {
IDE, API, SETUP, INIT
}
private enum theSystem {
WIN, MAC, LUX, FOO
}
private static RunTime runTime = null;
private static int debugLevelSaved;
private static String debugLogfileSaved;
public static boolean testing = false;
public static boolean testingWinApp = false;
public Type runType = Type.INIT;
public String sxBuild = "";
public String sxBuildStamp = "";
public String jreVersion = java.lang.System.getProperty("java.runtime.version");
public Preferences optionsIDE = null;
public ClassLoader classLoader = RunTime.class.getClassLoader();
public String baseJar = "";
public String userName = "";
public String fpBaseTempPath = "";
private Class clsRef = RunTime.class;
private Class clsRefBase = clsRef;
private List<URL> classPath = new ArrayList<URL>();
public File fTempPath = null;
public File fBaseTempPath = null;
public File fLibsFolder = null;
public String fpJarLibs = "/sikulixlibs/";
public String fpSysLibs = null;
boolean areLibsExported = false;
private Map<String, Boolean> libsLoaded = new HashMap<String, Boolean>();
public File fUserDir = null;
public File fWorkDir = null;
public File fTestFolder = null;
public File fTestFile = null;
public File fAppPath = null;
public File fSikulixAppPath = null;
public File fSikulixExtensions = null;
public String[] standardExtensions = new String[]{"selenium4sikulix"};
public File fSikulixLib = null;
public File fSikulixStore;
public File fSikulixDownloadsGeneric = null;
public File fSikulixDownloadsBuild = null;
public File fSikulixSetup;
private File fOptions = null;
private Properties options = null;
private String fnOptions = "SikulixOptions.txt";
private String fnPrefs = "SikulixPreferences.txt";
public File fSxBase = null;
public File fSxBaseJar = null;
public File fSxProject = null;
public File fSxProjectTestScriptsJS = null;
public File fSxProjectTestScripts = null;
public String fpContent = "sikulixcontent";
public boolean runningJar = true;
public boolean runningInProject = false;
public boolean runningWindows = false;
public boolean runningMac = false;
public boolean runningLinux = false;
public boolean runningWinApp = false;
public boolean runningMacApp = false;
private theSystem runningOn = theSystem.FOO;
private final String osNameSysProp = System.getProperty("os.name");
private final String osVersionSysProp = System.getProperty("os.version");
public String javaShow = "not-set";
public int javaArch = 32;
public int javaVersion = 0;
public String javahome = FileManager.slashify(System.getProperty("java.home"), false);
public String osName = "NotKnown";
public String sysName = "NotKnown";
public String osVersion = "";
private String appType = null;
public int debuglevelAPI = -1;
private boolean runningScripts = false;
public String linuxDistro = "???LINUX???";
public String linuxNeededLibs = "";
//</editor-fold>
GraphicsEnvironment genv = null;
GraphicsDevice[] gdevs;
public Rectangle[] monitorBounds = null;
Rectangle rAllMonitors;
int mainMonitor = -1;
int nMonitors = 0;
Point pNull = new Point(0, 0);
//<editor-fold defaultstate="collapsed" desc="global init">
private void init(Type typ) {
//<editor-fold defaultstate="collapsed" desc="general">
if ("winapp".equals(getOption("testing"))) {
log(lvl, "***** for testing: simulating WinApp");
testingWinApp = true;
}
for (String line : preLogMessages.split(";")) {
if (!line.isEmpty()) {
log(lvl, line);
}
}
log(lvl, "global init: entering as: %s", typ);
sxBuild = SikuliVersionBuild;
sxBuildStamp = sxBuild.replace("_", "").replace("-", "").replace(":", "").substring(0, 12);
if (System.getProperty("user.name") != null) {
userName = System.getProperty("user.name");
}
if (userName.isEmpty()) {
userName = "unknown";
}
String tmpdir = System.getProperty("java.io.tmpdir");
if (tmpdir != null && !tmpdir.isEmpty()) {
fTempPath = new File(tmpdir);
} else {
terminate(1, "init: java.io.tmpdir not valid (null or empty");
}
fBaseTempPath = new File(fTempPath,
String.format("Sikulix_%d", FileManager.getRandomInt()));
fpBaseTempPath = fBaseTempPath.getAbsolutePath();
fBaseTempPath.mkdirs();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
isTerminating = true;
log(lvl, "final cleanup");
if (isRunning != null) {
try {
isRunningFile.close();
} catch (IOException ex) {
}
isRunning.delete();
}
if (shouldCleanDownloads) {
FileManager.deleteFileOrFolder(fSikulixDownloadsBuild);
}
for (File f : fTempPath.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File aFile = new File(dir, name);
boolean isObsolete = false;
long lastTime = aFile.lastModified();
if (lastTime == 0) {
return false;
}
if (lastTime < ((new Date().getTime()) - 7 * 24 * 60 * 60 * 1000)) {
isObsolete = true;
}
if (name.contains("BridJExtractedLibraries") && isObsolete) {
return true;
}
if (name.toLowerCase().contains("sikuli")) {
if (name.contains("Sikulix_")) {
if (isObsolete || aFile.equals(fBaseTempPath)) {
return true;
}
} else {
return true;
}
}
return false;
}
})) {
Debug.log(4, "cleanTemp: " + f.getName());
FileManager.deleteFileOrFolder(f.getAbsolutePath());
}
}
});
if (Type.IDE.equals(typ) && !runningScripts) {
isRunning = new File(fTempPath, isRunningFilename);
boolean shouldTerminate = false;
try {
isRunning.createNewFile();
isRunningFile = new FileOutputStream(isRunning);
if (null == isRunningFile.getChannel().tryLock()) {
Sikulix.popError("Terminating: IDE already running");
shouldTerminate = true;
}
} catch (Exception ex) {
Sikulix.popError("Terminating on FatalError: cannot access IDE lock for/n" + isRunning);
shouldTerminate = true;
}
if (shouldTerminate) {
System.exit(1);
}
}
for (String aFile : fTempPath.list()) {
if ((aFile.startsWith("Sikulix") && (new File(aFile).isFile()))
|| (aFile.startsWith("jffi") && aFile.endsWith(".tmp"))) {
FileManager.deleteFileOrFolder(new File(fTempPath, aFile));
}
}
try {
if (!fSikulixAppPath.exists()) {
fSikulixAppPath.mkdirs();
}
if (!fSikulixAppPath.exists()) {
terminate(1, appDataMsg, fSikulixAppPath);
}
fSikulixExtensions = new File(fSikulixAppPath, "Extensions");
fSikulixLib = new File(fSikulixAppPath, "Lib");
fSikulixDownloadsGeneric = new File(fSikulixAppPath, "SikulixDownloads");
fSikulixSetup = new File(fSikulixAppPath, "SikulixSetup");
fLibsProvided = new File(fSikulixAppPath, fpSysLibs);
fLibsLocal = fLibsProvided.getParentFile().getParentFile();
fSikulixExtensions.mkdir();
fSikulixDownloadsGeneric.mkdir();
} catch (Exception ex) {
terminate(1, appDataMsg + "\n" + ex.toString(), fSikulixAppPath);
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="monitors">
if (!isHeadless()) {
genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
gdevs = genv.getScreenDevices();
nMonitors = gdevs.length;
if (nMonitors == 0) {
terminate(1, "GraphicsEnvironment has no ScreenDevices");
}
monitorBounds = new Rectangle[nMonitors];
rAllMonitors = null;
Rectangle currentBounds;
for (int i = 0; i < nMonitors; i++) {
currentBounds = gdevs[i].getDefaultConfiguration().getBounds();
if (null != rAllMonitors) {
rAllMonitors = rAllMonitors.union(currentBounds);
} else {
rAllMonitors = currentBounds;
}
if (currentBounds.contains(pNull)) {
if (mainMonitor < 0) {
mainMonitor = i;
log(lvl, "ScreenDevice %d has (0,0) --- will be primary Screen(0)", i);
} else {
log(lvl, "ScreenDevice %d too contains (0,0)!", i);
}
}
log(lvl, "Monitor %d: (%d, %d) %d x %d", i,
currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height);
monitorBounds[i] = currentBounds;
}
if (mainMonitor < 0) {
log(lvl, "No ScreenDevice has (0,0) --- using 0 as primary: %s", monitorBounds[0]);
mainMonitor = 0;
}
} else {
log(lvl, "running in headless environment");
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="classpath">
try {
if (Type.IDE.equals(typ)) {
clsRef = Class.forName("org.sikuli.ide.SikuliIDE");
} else if (Type.SETUP.equals(typ)) {
clsRef = Class.forName("org.sikuli.setup.RunSetup");
}
} catch (Exception ex) {
}
CodeSource codeSrc = clsRef.getProtectionDomain().getCodeSource();
String base = null;
if (codeSrc != null && codeSrc.getLocation() != null) {
base = FileManager.slashify(codeSrc.getLocation().getPath(), false);
}
appType = "from a jar";
if (base != null) {
fSxBaseJar = new File(base);
String jn = fSxBaseJar.getName();
fSxBase = fSxBaseJar.getParentFile();
log(lvl, "runs as %s in: %s", jn, fSxBase.getAbsolutePath());
if (jn.contains("classes")) {
runningJar = false;
fSxProject = fSxBase.getParentFile().getParentFile();
log(lvl, "not jar - supposing Maven project: %s", fSxProject);
appType = "in Maven project from classes";
runningInProject = true;
} else if ("target".equals(fSxBase.getName())) {
fSxProject = fSxBase.getParentFile().getParentFile();
log(lvl, "folder target detected - supposing Maven project: %s", fSxProject);
appType = "in Maven project from some jar";
runningInProject = true;
} else {
if (runningWindows) {
if (jn.endsWith(".exe")) {
runningWinApp = true;
runningJar = false;
appType = "as application .exe";
}
} else if (runningMac) {
if (fSxBase.getAbsolutePath().contains("SikuliX.app/Content")) {
runningMacApp = true;
appType = "as application .app";
if (!fSxBase.getAbsolutePath().startsWith("/Applications")) {
appType += " (not from /Applications folder)";
}
}
}
}
} else {
terminate(1, "no valid Java context for SikuliX available "
+ "(java.security.CodeSource.getLocation() is null)");
}
if (runningInProject) {
fSxProjectTestScriptsJS = new File(fSxProject, "StuffContainer/testScripts/testJavaScript");
fSxProjectTestScripts = new File(fSxProject, "StuffContainer/testScripts");
}
List<String> items = new ArrayList<String>();
if (Type.API.equals(typ)) {
String optJython = getOption("jython");
if (!optJython.isEmpty()) {
items.add(optJython);
}
}
if (!Type.SETUP.equals(typ)) {
String optClasspath = getOption("classpath");
if (!optClasspath.isEmpty()) {
items.addAll(Arrays.asList(optClasspath.split(System.getProperty("path.separator"))));
}
items.addAll(Arrays.asList(standardExtensions));
if (items.size() > 0) {
String[] fList = fSikulixExtensions.list();
for (String item : items) {
item = item.trim();
if (new File(item).isAbsolute()) {
addToClasspath(item);
} else {
for (String fpFile : fList) {
File fFile = new File(fSikulixExtensions, fpFile);
if (fFile.length() > 0) {
if (fpFile.startsWith(item)) {
addToClasspath(fFile.getAbsolutePath());
break;
}
} else {
fFile.delete();
}
}
}
}
}
}
//</editor-fold>
if (runningWinApp || testingWinApp) {
runTime.fpJarLibs += "windows";
runTime.fpSysLibs = runTime.fpJarLibs.substring(1) + "/libs" + runTime.javaArch;
}
if (!Type.SETUP.equals(typ)) {
libsExport(typ);
} else {
fSikulixDownloadsBuild = new File(fSikulixAppPath, "SikulixDownloads_" + sxBuildStamp);
String[] fpList = fSikulixAppPath.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.contains("SikulixDownloads_")) {
if (name.contains(sxBuildStamp)) {
return false;
}
return true;
}
return false;
}
});
if (fpList.length > 0) {
log(lvl, "deleting versioned downloads folder in AppPath (%s)", fSikulixDownloadsBuild.getName());
for (String entry : fpList) {
//new File(fSikulixAppPath, entry).renameTo(fSikulixDownloadsBuild);
FileManager.deleteFileOrFolder(new File(fSikulixAppPath, entry));
}
}
}
runType = typ;
if (Debug.getDebugLevel() == minLvl) {
show();
}
log(lvl, "global init: leaving");
}
class LibsFilter implements FilenameFilter {
String sAccept = "";
public LibsFilter(String toAccept) {
sAccept = toAccept;
}
@Override
public boolean accept(File dir, String name) {
if (dir.getPath().contains(sAccept)) {
return true;
}
return false;
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="libs export">
public void makeFolders() {
fLibsFolder = new File(fSikulixAppPath, "SikulixLibs_" + sxBuildStamp);
if (testing) {
logp("***** for testing: delete folders SikulixLibs/ and Lib/");
FileManager.deleteFileOrFolder(fLibsFolder);
FileManager.deleteFileOrFolder(fSikulixLib);
}
if (!fLibsFolder.exists()) {
fLibsFolder.mkdirs();
if (!fLibsFolder.exists()) {
terminate(1, "libs folder not available: " + fLibsFolder.toString());
}
log(lvl, "new libs folder at: %s", fLibsFolder);
} else {
log(lvl, "exists libs folder at: %s", fLibsFolder);
}
String[] fpList = fTempPath.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.contains("SikulixLibs")) {
return true;
}
return false;
}
});
if (fpList.length > 0) {
log(lvl, "deleting obsolete libs folders in Temp");
for (String entry : fpList) {
if (entry.endsWith(sxBuildStamp)) {
continue;
}
FileManager.deleteFileOrFolder(new File(fTempPath, entry));
}
}
fpList = fSikulixAppPath.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.contains("SikulixLibs")) {
return true;
}
return false;
}
});
if (fpList.length > 1) {
log(lvl, "deleting obsolete libs folders in AppPath");
for (String entry : fpList) {
if (entry.endsWith(sxBuildStamp)) {
continue;
}
FileManager.deleteFileOrFolder(new File(fSikulixAppPath, entry));
}
}
}
private boolean libsLoad(String libName) {
if (!areLibsExported) {
libsExport(runType);
}
if (!areLibsExported) {
terminate(1, "loadLib: deferred exporting of libs did not work");
}
if (runningWindows) {
libName += ".dll";
} else if (runningMac) {
libName = "lib" + libName + ".dylib";
} else if (runningLinux) {
libName = "lib" + libName + ".so";
}
File fLib = new File(fLibsFolder, libName);
Boolean vLib = libsLoaded.get(libName);
if (vLib == null || !fLib.exists()) {
terminate(1, String.format("loadlib: %s not available in %s", libName, fLibsFolder));
}
String msg = "loadLib: %s";
int level = lvl;
if (vLib) {
level++;
msg += " already loaded";
}
if (vLib) {
log(level, msg, libName);
return true;
}
boolean shouldTerminate = false;
Error loadError = null;
while (!shouldTerminate) {
shouldTerminate = true;
loadError = null;
try {
System.load(new File(fLibsFolder, libName).getAbsolutePath());
} catch (Error e) {
loadError = e;
if (runningLinux) {
log(-1, msg + " not usable: \n%s", libName, loadError);
shouldTerminate = !LinuxSupport.checkAllLibs();
}
}
}
if (loadError != null) {
log(-1, "Problematic lib: %s (...TEMP...)", fLib);
log(-1, "%s loaded, but it might be a problem with needed dependent libraries\nERROR: %s",
libName, loadError.getMessage().replace(fLib.getAbsolutePath(), "...TEMP..."));
if (Settings.runningSetup) {
return false;
}
else {
terminate(1, "problem with native library: " + libName);
}
}
libsLoaded.put(libName, true);
log(level, msg, libName);
return true;
}
private boolean libsCheck(File flibsFolder) {
// 1.1-MadeForSikuliX64M.txt
String name = String.format("1.1-MadeForSikuliX%d%s.txt", javaArch, runningOn.toString().substring(0, 1));
if (!new File(flibsFolder, name).exists()) {
log(lvl, "libs folder empty or has wrong content");
return false;
}
return true;
}
private void libsExport(Type typ) {
shouldExport = false;
makeFolders();
URL uLibsFrom = null;
if (!libsCheck(fLibsFolder)) {
FileManager.deleteFileOrFolder(fLibsFolder);
fLibsFolder.mkdirs();
shouldExport = true;
if (!fLibsFolder.exists()) {
terminate(1, "libs folder not available: " + fLibsFolder.toString());
}
}
if (shouldExport) {
String sysShort = "win";
boolean shouldAddLibsJar = false;
if (!runningWinApp && !testingWinApp) {
sysShort = runningOn.toString().toLowerCase();
}
String fpLibsFrom = "";
if (runningJar) {
fpLibsFrom = fSxBaseJar.getAbsolutePath();
if (fpLibsFrom.contains("forsetup")) {
shouldAddLibsJar = true;
}
} else {
String fSrcFolder = typ.toString();
if (Type.SETUP.toString().equals(fSrcFolder)) {
fSrcFolder = "Setup";
}
fpLibsFrom = fSxBaseJar.getPath().replace(fSrcFolder, "Libs" + sysShort) + "/";
}
if (testing && !runningJar) {
if (testingWinApp || testSwitch()) {
logp("***** for testing: exporting from classes");
} else {
logp("***** for testing: exporting from jar");
shouldAddLibsJar = true;
}
}
if (!shouldAddLibsJar &&
(null != isJarOnClasspath("sikulix.jar") || null != isJarOnClasspath("sikulixapi.jar"))) {
shouldAddLibsJar = false;
fpLibsFrom = "";
}
if (shouldAddLibsJar) {
fpLibsFrom = new File(fSxProject,
String.format("Libs%s/target/sikulixlibs%s-1.1.2.jar", sysShort, sysShort)).getAbsolutePath();
}
log(lvl, "now exporting libs");
if (!fpLibsFrom.isEmpty()) {
addToClasspath(fpLibsFrom);
}
uLibsFrom = clsRef.getResource(fpJarLibs);
if (testing || uLibsFrom == null) {
dumpClassPath();
}
if (uLibsFrom == null) {
terminate(1, "libs to export not found on above classpath: " + fpJarLibs);
}
log(lvl, "libs to export are at:\n%s", uLibsFrom);
if (runningWinApp || testingWinApp) {
String libsAccepted = "libs" + javaArch;
extractResourcesToFolder(fpJarLibs, fLibsFolder, new LibsFilter(libsAccepted));
File fCurrentLibs = new File(fLibsFolder, libsAccepted);
if (FileManager.xcopy(fCurrentLibs, fLibsFolder)) {
FileManager.deleteFileOrFolder(fCurrentLibs);
} else {
terminate(1, "could not create libs folder for Windows --- see log");
}
} else {
extractResourcesToFolder(fpJarLibs, fLibsFolder, null);
}
}
for (String aFile : fLibsFolder.list()) {
libsLoaded.put(aFile, false);
}
if (useLibsProvided) {
log(lvl, "Linux: requested to use provided libs - copying");
LinuxSupport.copyProvidedLibs(fLibsFolder);
}
if (runningWindows) {
addToWindowsSystemPath(fLibsFolder);
if (!checkJavaUsrPath(fLibsFolder)) {
log(-1, "Problems setting up on Windows - see errors - might not work and crash later");
}
String lib = "jawt.dll";
File fJawtDll = new File(fLibsFolder, lib);
FileManager.deleteFileOrFolder(fJawtDll);
FileManager.xcopy(new File(javahome + "/bin/" + lib), fJawtDll);
if (!fJawtDll.exists()) {
terminate(1, "problem copying %s", fJawtDll);
}
}
areLibsExported = true;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="native libs handling">
/**
* INTERNAL USE: load a native library from the libs folder
*
* @param libname name of library without prefix/suffix/ending
*/
public static void loadLibrary(String libname) {
if (isTerminating) {
return;
}
RunTime.get().libsLoad(libname);
}
/**
* INTERNAL USE: load a native library from the libs folder
*
* @param libname name of library without prefix/suffix/ending
*/
public static boolean loadLibrary(String libname, boolean useLibsProvided) {
RunTime rt = RunTime.get();
rt.useLibsProvided = useLibsProvided;
return rt.libsLoad(libname);
}
private void addToWindowsSystemPath(File fLibsFolder) {
String syspath = SysJNA.WinKernel32.getEnvironmentVariable("PATH");
if (syspath == null) {
terminate(1, "addToWindowsSystemPath: cannot access system path");
} else {
String libsPath = (fLibsFolder.getAbsolutePath()).replaceAll("/", "\\");
if (!syspath.toUpperCase().contains(libsPath.toUpperCase())) {
if (SysJNA.WinKernel32.setEnvironmentVariable("PATH", libsPath + ";" + syspath)) {
syspath = SysJNA.WinKernel32.getEnvironmentVariable("PATH");
if (!syspath.toUpperCase().contains(libsPath.toUpperCase())) {
log(-1, "addToWindowsSystemPath: adding to system path did not work:\n%s", syspath);
terminate(1, "addToWindowsSystemPath: did not work - see error");
}
}
log(lvl, "addToWindowsSystemPath: added to systempath:\n%s", libsPath);
}
}
}
private boolean checkJavaUsrPath(File fLibsFolder) {
String fpLibsFolder = fLibsFolder.getAbsolutePath();
Field usrPathsField = null;
boolean contained = false;
try {
usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
} catch (NoSuchFieldException ex) {
log(-1, "checkJavaUsrPath: get\n%s", ex);
} catch (SecurityException ex) {
log(-1, "checkJavaUsrPath: get\n%s", ex);
}
if (usrPathsField != null) {
usrPathsField.setAccessible(true);
try {
//get array of paths
String[] javapaths = (String[]) usrPathsField.get(null);
//check if the path to add is already present
for (String p : javapaths) {
if (new File(p).equals(fLibsFolder)) {
contained = true;
break;
}
}
//add the new path
if (!contained) {
final String[] newPaths = Arrays.copyOf(javapaths, javapaths.length + 1);
newPaths[newPaths.length - 1] = fpLibsFolder;
usrPathsField.set(null, newPaths);
log(lvl, "checkJavaUsrPath: added to ClassLoader.usrPaths");
contained = true;
}
} catch (IllegalAccessException ex) {
log(-1, "checkJavaUsrPath: set\n%s", ex);
} catch (IllegalArgumentException ex) {
log(-1, "checkJavaUsrPath: set\n%s", ex);
}
return contained;
}
return false;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="init for IDE">
File isRunning = null;
FileOutputStream isRunningFile = null;
String isRunningFilename = "s_i_k_u_l_i-ide-isrunning";
private void initIDEbefore() {
log(lvl, "initIDEbefore: entering");
optionsIDE = Preferences.userNodeForPackage(Sikulix.class);
if (jreVersion.startsWith("1.6")) {
String jyversion = "";
Properties prop = new Properties();
String fp = "org/python/version.properties";
InputStream ifp = null;
try {
ifp = classLoader.getResourceAsStream(fp);
if (ifp != null) {
prop.load(ifp);
ifp.close();
jyversion = prop.getProperty("jython.version");
}
} catch (IOException ex) {
}
if (!jyversion.isEmpty() && !jyversion.startsWith("2.5")) {
Sikulix.popError(String.format("The bundled Jython %s\n"
+ "cannot be used on Java 6!\n"
+ "Run setup again in this environment.\n"
+ "Click OK to terminate now", jyversion));
System.exit(1);
}
}
Settings.isRunningIDE = true;
if (runningMac) {
System.setProperty("apple.laf.useScreenMenuBar", "true");
if (!runningMacApp && !runningInProject) {
if (!Sikulix.popAsk("This use of SikuliX is not supported\n"
+ "and might lead to misbehavior!\n"
+ "Click YES to continue (you should be sure)\n"
+ "Click NO to terminate and check the situation.")) {
System.exit(1);
}
}
}
log(lvl, "initIDEbefore: leaving");
}
private void initIDEafter() {
// log(lvl, "initIDEafter: entering");
// log(lvl, "initIDEafter: leaving");
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="init for API">
private void initAPI() {
log(lvl, "initAPI: entering");
if (shouldExport
|| !fSikulixLib.exists()
|| !new File(fSikulixLib, "robot").exists()
|| !new File(fSikulixLib, "sikuli").exists()) {
fSikulixLib.mkdir();
extractResourcesToFolder("Lib", fSikulixLib, null);
} else {
extractResourcesToFolder("Lib/sikuli", new File(fSikulixLib, "sikuli"), null);
}
log(lvl, "initAPI: leaving");
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="init for Setup">
private void initSetup() {
// log(lvl, "initSetup: entering");
// log(lvl, "initSetup: leaving");
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="helpers">
/**
* INTERNAL USE: to check whether we are running in compiled classes context
*
* @return true if the code source location is a folder ending with classes (Maven convention)
*/
public boolean isRunningFromJar() {
return runningJar;
}
/**
* @return return true if Java version > 7
*/
public boolean isJava8() {
return javaVersion > 7;
}
/**
* @return return true if Java version > 6
*/
public boolean isJava7() {
return javaVersion > 6;
}
public boolean isOSX10() {
return osVersion.startsWith("10.10.") || osVersion.startsWith("10.11.") || osVersion.startsWith("10.12.");
}
public boolean needsRobotFake() {
return !Settings.ClickFast && runningMac && isOSX10();
}
/**
* print out some basic information about the current runtime environment
*/
public void show() {
if (hasOptions()) {
dumpOptions();
}
logp("***** show environment for %s (build %s)", runType, sxBuildStamp);
logp("user.home: %s", fUserDir);
logp("user.dir (work dir): %s", fWorkDir);
logp("user.name: %s", userName);
logp("java.io.tmpdir: %s", fTempPath);
logp("running %dBit on %s (%s) %s", javaArch, osName,
(linuxDistro.contains("???") ? osVersion : linuxDistro), appType);
logp(javaShow);
logp("app data folder: %s", fSikulixAppPath);
logp("libs folder: %s", fLibsFolder);
if (runningJar) {
logp("executing jar: %s", fSxBaseJar);
}
if (Debug.getDebugLevel() > minLvl - 1 || isJythonReady) {
dumpClassPath("sikulix");
if (isJythonReady) {
int saveLvl = Debug.getDebugLevel();
Debug.setDebugLevel(lvl);
JythonHelper.get().showSysPath();
Screen.showMonitors();
Debug.setDebugLevel(saveLvl);
}
}
logp("***** show environment end");
}
public boolean testSwitch() {
if (0 == (new Date().getTime() / 10000) % 2) {
return true;
}
return false;
}
public String getVersionShortBasic() {
return sversion.substring(0, 3);
}
public String getVersionShort() {
if (SikuliVersionBetaN > 0 && SikuliVersionBetaN < 99) {
return bversion;
} else {
return sversion;
}
}
public String getSystemInfo() {
return String.format("%s/%s/%s", SikuliVersionLong, SikuliSystemVersion, SikuliJavaVersion);
}
public boolean isVersionRelease() {
return SikuliVersionType.isEmpty();
}
public String getVersion() {
return SikuliVersion;
}
public void getStatus() {
System.out.println("***** System Information Dump *****");
System.out.println(String.format("*** SystemInfo\n%s", getSystemInfo()));
System.getProperties().list(System.out);
System.out.println("*** System Environment");
for (String key : System.getenv().keySet()) {
System.out.println(String.format("%s = %s", key, System.getenv(key)));
}
System.out.println("*** Java Class Path");
URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
URL[] urls = sysLoader.getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(String.format("%d: %s", i, urls[i]));
}
System.out.println("***** System Information Dump ***** end *****");
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="internal options handling">
private void loadOptions(Type typ) {
for (File aFile : new File[]{fWorkDir, fUserDir, fSikulixStore}) {
log(lvl, "loadOptions: check: %s", aFile);
fOptions = new File(aFile, fnOptions);
if (fOptions.exists()) {
break;
} else {
fOptions = null;
}
}
if (fOptions != null) {
options = new Properties();
try {
InputStream is;
is = new FileInputStream(fOptions);
options.load(is);
is.close();
} catch (Exception ex) {
log(-1, "while checking Options file:\n%s", fOptions);
fOptions = null;
options = null;
}
testing = isOption("testing", false);
if (testing) {
Debug.setDebugLevel(3);
}
log(lvl, "found Options file at: %s", fOptions);
}
if (hasOptions()) {
for (Object oKey : options.keySet()) {
String sKey = (String) oKey;
String[] parts = sKey.split("\\.");
if (parts.length == 1) {
continue;
}
String sClass = parts[0];
String sAttr = parts[1];
Class cClass = null;
Field cField = null;
Class ccField = null;
if (sClass.contains("Settings")) {
try {
cClass = Class.forName("org.sikuli.basics.Settings");
cField = cClass.getField(sAttr);
ccField = cField.getType();
if (ccField.getName() == "boolean") {
cField.setBoolean(null, isOption(sKey));
} else if (ccField.getName() == "int") {
cField.setInt(null, getOptionNumber(sKey));
} else if (ccField.getName() == "float") {
cField.setInt(null, getOptionNumber(sKey));
} else if (ccField.getName() == "double") {
cField.setInt(null, getOptionNumber(sKey));
} else if (ccField.getName() == "String") {
cField.set(null, getOption(sKey));
}
} catch (Exception ex) {
log(-1, "loadOptions: not possible: %s = %s", sKey, options.getProperty(sKey));
}
}
}
}
}
/**
* CONVENIENCE: look into the option file if any (if no option file is found, the option is taken as not existing)
*
* @param pName the option key (case-sensitive)
* @return true only if option exists and has yes or true (not case-sensitive), in all other cases false
*/
public boolean isOption(String pName) {
return isOption(pName, false);
}
/**
* CONVENIENCE: look into the option file if any (if no option file is found, the option is taken as not existing)
*
* @param pName the option key (case-sensitive)
* @param bDefault the default to be returned if option absent or empty
* @return true if option has yes or no, false for no or false (not case-sensitive)
*/
public boolean isOption(String pName, Boolean bDefault) {
if (options == null) {
return bDefault;
}
String pVal = options.getProperty(pName, bDefault.toString()).toLowerCase();
if (pVal.isEmpty()) {
return bDefault;
} else if (pVal.contains("yes") || pVal.contains("true") || pVal.contains("on")) {
return true;
} else if (pVal.contains("no") || pVal.contains("false") || pVal.contains("off")) {
return false;
}
return true;
}
/**
* look into the option file if any (if no option file is found, the option is taken as not existing)
*
* @param pName the option key (case-sensitive)
* @return the associated value, empty string if absent
*/
public String getOption(String pName) {
if (options == null) {
return "";
}
String pVal = options.getProperty(pName, "");
return pVal;
}
/**
* look into the option file if any (if no option file is found, the option is taken as not existing)<br>
* side-effect: if no options file is there, an options store will be created in memory<br>
* in this case and when the option is absent or empty, the given default will be stored<br>
* you might later save the options store to a file with storeOptions()
*
* @param pName the option key (case-sensitive)
* @param sDefault the default to be returned if option absent or empty
* @return the associated value, the default value if absent or empty
*/
public String getOption(String pName, String sDefault) {
if (options == null) {
options = new Properties();
options.setProperty(pName, sDefault);
return sDefault;
}
String pVal = options.getProperty(pName, sDefault);
if (pVal.isEmpty()) {
options.setProperty(pName, sDefault);
return sDefault;
}
return pVal;
}
/**
* store an option key-value pair, overwrites existing value<br>
* new option store is created if necessary and can later be saved to a file
*
* @param pName
* @param sValue
*/
public void setOption(String pName, String sValue) {
if (options == null) {
options = new Properties();
}
options.setProperty(pName, sValue);
}
/**
* CONVENIENCE: look into the option file if any (if no option file is found, the option is taken as not existing)<br>
* tries to convert the stored string value into an integer number (gives 0 if not possible)<br>
*
* @param pName the option key (case-sensitive)
* @return the converted integer number, 0 if absent or not possible
*/
public int getOptionNumber(String pName) {
if (options == null) {
return 0;
}
String pVal = options.getProperty(pName, "0");
int nVal = 0;
try {
nVal = Integer.decode(pVal);
} catch (Exception ex) {
}
return nVal;
}
/**
* CONVENIENCE: look into the option file if any (if no option file is found, the option is taken as not existing)<br>
* tries to convert the stored string value into an integer number (gives 0 if not possible)<br>
*
* @param pName the option key (case-sensitive)
* @param nDefault the default to be returned if option absent, empty or not convertable
* @return the converted integer number, default if absent, empty or not possible
*/
public int getOptionNumber(String pName, Integer nDefault) {
if (options == null) {
return nDefault;
}
String pVal = options.getProperty(pName, nDefault.toString());
int nVal = nDefault;
try {
nVal = Integer.decode(pVal);
} catch (Exception ex) {
}
return nVal;
}
/**
* all options and their values
*
* @return a map of key-value pairs containing the found options, empty if no options file found
*/
public Map<String, String> getOptions() {
Map<String, String> mapOptions = new HashMap<String, String>();
if (options != null) {
Enumeration<?> optionNames = options.propertyNames();
String optionName;
while (optionNames.hasMoreElements()) {
optionName = (String) optionNames.nextElement();
mapOptions.put(optionName, getOption(optionName));
}
}
return mapOptions;
}
/**
* check whether options are defined
*
* @return true if at lest one option defined else false
*/
public boolean hasOptions() {
return options != null && options.size() > 0;
}
/**
* all options and their values written to sysout as key = value
*/
public void dumpOptions() {
if (hasOptions()) {
logp("*** options dump:\n%s", (fOptions == null ? "" : fOptions));
for (String sOpt : getOptions().keySet()) {
logp("%s = %s", sOpt, getOption(sOpt));
}
logp("*** options dump end");
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Sikulix options handling">
public int SikuliVersionMajor;
public int SikuliVersionMinor;
public int SikuliVersionSub;
public int SikuliVersionBetaN;
public String SikuliProjectVersionUsed = "";
public String SikuliProjectVersion = "";
public String SikuliVersionBuild;
public String SikuliVersionType;
public String SikuliVersionTypeText;
public String downloadBaseDirBase;
public String downloadBaseDirWeb;
public String downloadBaseDir;
// used for download of production versions
private final String dlProdLink = "https://launchpad.net/raiman/sikulix2013+/";
private final String dlProdLink1 = ".0";
private final String dlProdLink2 = "/+download/";
// used for download of development versions (nightly builds)
private final String dlDevLink = "http://nightly.sikuli.de/";
public String SikuliRepo;
public String SikuliLocalRepo = "";
public String[] ServerList = {};
private String sversion;
private String bversion;
public String SikuliVersionDefault;
public String SikuliVersionBeta;
public String SikuliVersionDefaultIDE;
public String SikuliVersionBetaIDE;
public String SikuliVersionDefaultScript;
public String SikuliVersionBetaScript;
public String SikuliVersion;
public String SikuliVersionIDE;
public String SikuliVersionScript;
public String SikuliJythonVersion;
public String SikuliJythonVersion25 = "2.5.4-rc1";
public String SikuliJythonMaven;
public String SikuliJythonMaven25;
public String SikuliJython;
public String SikuliJython25;
public String SikuliJRubyVersion;
public String SikuliJRuby;
public String SikuliJRubyMaven;
public String dlMavenRelease = "https://repo1.maven.org/maven2/";
public String dlMavenSnapshot = "https://oss.sonatype.org/content/groups/public/";
public Map<String, String> tessData = new HashMap<String, String>();
//TODO needed ???
public final String libOpenCV = "libopencv_java248";
public String SikuliVersionLong;
public String SikuliSystemVersion;
public String SikuliJavaVersion;
private void initSikulixOptions() {
SikuliRepo = null;
Properties prop = new Properties();
String svf = "sikulixversion.txt";
try {
InputStream is;
is = clsRef.getClassLoader().getResourceAsStream("Settings/" + svf);
if (is == null) {
terminate(1, "initSikulixOptions: not found on classpath: %s", "Settings/" + svf);
}
prop.load(is);
is.close();
String svt = prop.getProperty("sikulixdev");
SikuliVersionMajor = Integer.decode(prop.getProperty("sikulixvmaj"));
SikuliVersionMinor = Integer.decode(prop.getProperty("sikulixvmin"));
SikuliVersionSub = Integer.decode(prop.getProperty("sikulixvsub"));
SikuliVersionBetaN = Integer.decode(prop.getProperty("sikulixbeta"));
String ssxbeta = "";
if (SikuliVersionBetaN > 0) {
ssxbeta = String.format("-Beta%d", SikuliVersionBetaN);
}
SikuliVersionBuild = prop.getProperty("sikulixbuild");
log(lvl + 1, "%s version from %s: %d.%d.%d%s build: %s", svf,
SikuliVersionMajor, SikuliVersionMinor, SikuliVersionSub, ssxbeta,
SikuliVersionBuild, svt);
sversion = String.format("%d.%d.%d",
SikuliVersionMajor, SikuliVersionMinor, SikuliVersionSub);
bversion = String.format("%d.%d.%d-Beta%d",
SikuliVersionMajor, SikuliVersionMinor, SikuliVersionSub, SikuliVersionBetaN);
SikuliVersionDefault = "SikuliX " + sversion;
SikuliVersionBeta = "Sikuli " + bversion;
SikuliVersionDefaultIDE = "SikulixIDE " + sversion;
SikuliVersionBetaIDE = "SikulixIDE " + bversion;
SikuliVersionDefaultScript = "SikulixScript " + sversion;
SikuliVersionBetaScript = "SikulixScript " + bversion;
SikuliVersionTypeText = "";
if ("release".equals(svt)) {
downloadBaseDirBase = dlProdLink;
downloadBaseDirWeb = downloadBaseDirBase + getVersionShortBasic() + dlProdLink1;
downloadBaseDir = downloadBaseDirWeb + dlProdLink2;
SikuliVersionType = "";
} else {
downloadBaseDirBase = dlDevLink;
downloadBaseDirWeb = dlDevLink;
downloadBaseDir = dlDevLink;
//TODO switch on for 1.1.2
//SikuliVersionTypeText = "nightly";
SikuliVersionBuild += SikuliVersionTypeText;
SikuliVersionType = svt;
}
if (SikuliVersionBetaN > 0) {
SikuliVersion = SikuliVersionBeta;
SikuliVersionIDE = SikuliVersionBetaIDE;
SikuliVersionScript = SikuliVersionBetaScript;
SikuliVersionLong = bversion + "(" + SikuliVersionBuild + ")";
} else {
SikuliVersion = SikuliVersionDefault;
SikuliVersionIDE = SikuliVersionDefaultIDE;
SikuliVersionScript = SikuliVersionDefaultScript;
SikuliVersionLong = sversion + "(" + SikuliVersionBuild + ")";
}
SikuliProjectVersionUsed = prop.getProperty("sikulixvused");
SikuliProjectVersion = prop.getProperty("sikulixvproject");
String osn = "UnKnown";
String os = System.getProperty("os.name").toLowerCase();
if (os.startsWith("mac")) {
osn = "Mac";
} else if (os.startsWith("windows")) {
osn = "Windows";
} else if (os.startsWith("linux")) {
osn = "Linux";
}
SikuliLocalRepo = FileManager.slashify(prop.getProperty("sikulixlocalrepo"), true);
SikuliJythonVersion = prop.getProperty("sikulixvjython");
SikuliJythonMaven = "org/python/jython-standalone/"
+ SikuliJythonVersion + "/jython-standalone-" + SikuliJythonVersion + ".jar";
SikuliJythonMaven25 = "org/python/jython-standalone/"
+ SikuliJythonVersion25 + "/jython-standalone-" + SikuliJythonVersion25 + ".jar";
SikuliJython = SikuliLocalRepo + SikuliJythonMaven;
SikuliJython25 = SikuliLocalRepo + SikuliJythonMaven25;
SikuliJRubyVersion = prop.getProperty("sikulixvjruby");
SikuliJRubyMaven = "org/jruby/jruby-complete/"
+ SikuliJRubyVersion + "/jruby-complete-" + SikuliJRubyVersion + ".jar";
SikuliJRuby = SikuliLocalRepo + SikuliJRubyMaven;
SikuliSystemVersion = osn + System.getProperty("os.version");
SikuliJavaVersion = "Java" + javaVersion + "(" + javaArch + ")" + jreVersion;
//TODO this should be in RunSetup only
//TODO debug version: where to do in sikulixapi.jar
//TODO need a function: reveal all environment and system information
// log(lvl, "%s version: downloading from %s", svt, downloadBaseDir);
} catch (Exception e) {
Debug.error("Settings: load version file %s did not work", svf);
Sikulix.endError(999);
}
// tessData.put("eng", "http://tesseract-ocr.googlecode.com/files/tesseract-ocr-3.02.eng.tar.gz");
tessData.put("eng", "http://download.sikulix.com/tesseract-ocr-3.02.eng.tar.gz");
Env.setSikuliVersion(SikuliVersion);
}
//</editor-fold>
//<editor-fold desc="user public options support">
private static String optThisComingFromFile = "thisOptions.comingFromWhatFile";
private static String optThisWhatIsANumber = "thisOptions.whatIsAnumber";
private static String whatIsANumber = "#";
private static boolean optIsNumber(Properties props, String pName) {
String prefix = getOpt(props, pName, whatIsANumber);
if (pName.contains(prefix)) {
return true;
}
return false;
}
/**
* load a properties file
*
* @param fpOptions path to a file containing options
* @return the Properties store or null
*/
public Properties loadOpts(String fpOptions) {
if (fpOptions == null) {
log(-1, "loadOptions: (error: no file)");
return null;
}
File fOptions = new File(fpOptions);
if (!fOptions.isFile()) {
log(-1, "loadOptions: (error: not found) %s", fOptions);
return null;
}
Properties pOptions = new Properties();
try {
fpOptions = fOptions.getCanonicalPath();
InputStream is;
is = new FileInputStream(fOptions);
pOptions.load(is);
is.close();
} catch (Exception ex) {
log(-1, "loadOptions: %s (error %s)", fOptions, ex.getMessage());
return null;
}
log(lvl, "loadOptions: ok (%d): %s", pOptions.size(), fOptions.getName());
pOptions.setProperty(optThisComingFromFile, fpOptions);
return pOptions;
}
public static Properties makeOpts() {
return new Properties();
}
/**
* save a properties store to a file (prop: this.comingfrom = abs. filepath)
*
* @param pOptions the prop store
* @return success
*/
public boolean saveOpts(Properties pOptions) {
String fpOptions = pOptions.getProperty(optThisComingFromFile);
if (null == fpOptions) {
log(-1, "saveOptions: no prop %s", optThisComingFromFile);
return false;
}
return saveOpts(pOptions, fpOptions);
}
/**
* save a properties store to the given file
*
* @param pOptions the prop store
* @param fpOptions path to a file
* @return success
*/
public boolean saveOpts(Properties pOptions, String fpOptions) {
pOptions.remove(optThisComingFromFile);
File fOptions = new File(fpOptions);
try {
fpOptions = fOptions.getCanonicalPath();
OutputStream os;
os = new FileOutputStream(fOptions);
pOptions.store(os, "");
os.close();
} catch (Exception ex) {
log(-1, "saveOptions: %s (error %s)", fOptions, ex.getMessage());
return false;
}
log(lvl, "saveOptions: saved: %s", fpOptions);
return true;
}
public static boolean hasOpt(Properties props, String pName) {
return null != props && null != props.getProperty(pName);
}
public static String getOpt(Properties props, String pName) {
return getOpt(props, pName, "");
}
public static String getOpt(Properties props, String pName, String deflt) {
String retVal = deflt;
if (hasOpt(props, pName)) {
retVal = props.getProperty(pName);
}
return retVal;
}
public static String setOpt(Properties props, String pName, String pVal) {
String retVal = "";
if (hasOpt(props, pName)) {
retVal = props.getProperty(pName);
}
props.setProperty(pName, pVal);
return retVal;
}
public static double getOptNum(Properties props, String pName) {
return getOptNum(props, pName, 0d);
}
public static double getOptNum(Properties props, String pName, double deflt) {
double retVal = deflt;
if (hasOpt(props, pName)) {
try {
retVal = Double.parseDouble(props.getProperty(pName));
} catch (Exception ex) {
}
}
return retVal;
}
public static double setOptNum(Properties props, String pName, double pVal) {
double retVal = 0d;
if (hasOpt(props, pName)) {
try {
retVal = Double.parseDouble(props.getProperty(pName));
} catch (Exception ex) {
}
}
props.setProperty(pName, ((Double) pVal).toString());
return retVal;
}
public static String delOpt(Properties props, String pName) {
String retVal = "";
if (hasOpt(props, pName)) {
retVal = props.getProperty(pName);
}
props.remove(pName);
return retVal;
}
public static Map<String, String> getOpts(Properties props) {
Map<String, String> mapOptions = new HashMap<String, String>();
if (props != null) {
Enumeration<?> optionNames = props.propertyNames();
String optionName;
while (optionNames.hasMoreElements()) {
optionName = (String) optionNames.nextElement();
mapOptions.put(optionName, props.getProperty(optionName));
}
}
return mapOptions;
}
public static int setOpts(Properties props, Map<String, String> aMap) {
int n = 0;
for (String key : aMap.keySet()) {
props.setProperty(key, aMap.get(key));
n++;
}
return n;
}
public static boolean delOpts(Properties props) {
if (null != props) {
props.clear();
return true;
}
return false;
}
public static int hasOpts(Properties props) {
if (null != props) {
return props.size();
}
return 0;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="handling resources from classpath">
protected List<String> extractTessData(File folder) {
List<String> files = new ArrayList<String>();
String tessdata = "/sikulixtessdata";
URL uContentList = clsRef.getResource(tessdata + "/" + fpContent);
if (uContentList != null) {
files = doResourceListWithList(tessdata, files, null);
if (files.size() > 0) {
files = doExtractToFolderWithList(tessdata, folder, files);
}
} else {
files = extractResourcesToFolder("/sikulixtessdata", folder, null);
}
return (files.size() == 0 ? null : files);
}
/**
* export all resource files from the given subtree on classpath to the given folder retaining the subtree<br>
* to export a specific file from classpath use extractResourceToFile or extractResourceToString
*
* @param fpRessources path of the subtree relative to root
* @param fFolder folder where to export (if null, only list - no export)
* @param filter implementation of interface FilenameFilter or null for no filtering
* @return the filtered list of files (compact sikulixcontent format)
*/
public List<String> extractResourcesToFolder(String fpRessources, File fFolder, FilenameFilter filter) {
List<String> content = null;
content = resourceList(fpRessources, filter);
if (content == null) {
return null;
}
if (fFolder == null) {
return content;
}
return doExtractToFolderWithList(fpRessources, fFolder, content);
}
private List<String> doExtractToFolderWithList(String fpRessources, File fFolder, List<String> content) {
int count = 0;
int ecount = 0;
String subFolder = "";
if (content != null && content.size() > 0) {
for (String eFile : content) {
if (eFile == null) {
continue;
}
if (eFile.endsWith("/")) {
subFolder = eFile.substring(0, eFile.length() - 1);
continue;
}
if (!subFolder.isEmpty()) {
eFile = new File(subFolder, eFile).getPath();
}
if (extractResourceToFile(fpRessources, eFile, fFolder)) {
log(lvl + 1, "extractResourceToFile done: %s", eFile);
count++;
} else {
ecount++;
}
}
}
if (ecount > 0) {
log(lvl, "files exported: %d - skipped: %d from %s to:\n %s", count, ecount, fpRessources, fFolder);
} else {
log(lvl, "files exported: %d from: %s to:\n %s", count, fpRessources, fFolder);
}
return content;
}
/**
* export all resource files from the given subtree in given jar to the given folder retaining the subtree
*
* @param aJar absolute path to an existing jar or a string identifying the jar on classpath (no leading /)
* @param fpRessources path of the subtree or file relative to root
* @param fFolder folder where to export (if null, only list - no export)
* @param filter implementation of interface FilenameFilter or null for no filtering
* @return the filtered list of files (compact sikulixcontent format)
*/
public List<String> extractResourcesToFolderFromJar(String aJar, String fpRessources, File fFolder, FilenameFilter filter) {
List<String> content = new ArrayList<String>();
File faJar = new File(aJar);
URL uaJar = null;
fpRessources = FileManager.slashify(fpRessources, false);
if (faJar.isAbsolute()) {
if (!faJar.exists()) {
log(-1, "extractResourcesToFolderFromJar: does not exist:\n%s", faJar);
return null;
}
try {
uaJar = new URL("jar", null, "file:" + aJar);
logp("%s", uaJar);
} catch (MalformedURLException ex) {
log(-1, "extractResourcesToFolderFromJar: bad URL for:\n%s", faJar);
return null;
}
} else {
uaJar = fromClasspath(aJar);
if (uaJar == null) {
log(-1, "extractResourcesToFolderFromJar: not on classpath: %s", aJar);
return null;
}
try {
String sJar = "file:" + uaJar.getPath() + "!/";
uaJar = new URL("jar", null, sJar);
} catch (MalformedURLException ex) {
log(-1, "extractResourcesToFolderFromJar: bad URL for:\n%s", uaJar);
return null;
}
}
content = doResourceListJar(uaJar, fpRessources, content, filter);
if (fFolder == null) {
return content;
}
copyFromJarToFolderWithList(uaJar, fpRessources, content, fFolder);
return content;
}
/**
* store a resource found on classpath to a file in the given folder with same filename
*
* @param inPrefix a subtree found in classpath
* @param inFile the filename combined with the prefix on classpath
* @param outDir a folder where to export
* @return success
*/
public boolean extractResourceToFile(String inPrefix, String inFile, File outDir) {
return extractResourceToFile(inPrefix, inFile, outDir, "");
}
/**
* store a resource found on classpath to a file in the given folder
*
* @param inPrefix a subtree found in classpath
* @param inFile the filename combined with the prefix on classpath
* @param outDir a folder where to export
* @param outFile the filename for export
* @return success
*/
public boolean extractResourceToFile(String inPrefix, String inFile, File outDir, String outFile) {
InputStream aIS;
FileOutputStream aFileOS;
String content = inPrefix + "/" + inFile;
try {
content = runningWindows ? content.replace("\\", "/") : content;
if (!content.startsWith("/")) {
content = "/" + content;
}
aIS = (InputStream) clsRef.getResourceAsStream(content);
if (aIS == null) {
throw new IOException("resource not accessible");
}
File out = outFile.isEmpty() ? new File(outDir, inFile) : new File(outDir, inFile);
if (!out.getParentFile().exists()) {
out.getParentFile().mkdirs();
}
aFileOS = new FileOutputStream(out);
copy(aIS, aFileOS);
aIS.close();
aFileOS.close();
} catch (Exception ex) {
log(-1, "extractResourceToFile: %s\n%s", content, ex);
return false;
}
return true;
}
/**
* store the content of a resource found on classpath in the returned string
*
* @param inPrefix a subtree from root found in classpath (leading /)
* @param inFile the filename combined with the prefix on classpath
* @param encoding
* @return file content
*/
public String extractResourceToString(String inPrefix, String inFile, String encoding) {
InputStream aIS = null;
String out = null;
String content = inPrefix + "/" + inFile;
if (!content.startsWith("/")) {
content = "/" + content;
}
try {
content = runningWindows ? content.replace("\\", "/") : content;
aIS = (InputStream) clsRef.getResourceAsStream(content);
if (aIS == null) {
throw new IOException("resource not accessible");
}
if (encoding == null) {
encoding = "UTF-8";
out = new String(copy(aIS));
} else if (encoding.isEmpty()) {
out = new String(copy(aIS), "UTF-8");
} else {
out = new String(copy(aIS), encoding);
}
aIS.close();
aIS = null;
} catch (Exception ex) {
log(-1, "extractResourceToString as %s from:\n%s\n%s", encoding, content, ex);
}
try {
if (aIS != null) {
aIS.close();
}
} catch (Exception ex) {
}
return out;
}
public URL resourceLocation(String folderOrFile) {
log(lvl, "resourceLocation: (%s) %s", clsRef, folderOrFile);
if (!folderOrFile.startsWith("/")) {
folderOrFile = "/" + folderOrFile;
}
return clsRef.getResource(folderOrFile);
}
private List<String> resourceList(String folder, FilenameFilter filter) {
log(lvl, "resourceList: enter");
List<String> files = new ArrayList<String>();
if (!folder.startsWith("/")) {
folder = "/" + folder;
}
URL uFolder = resourceLocation(folder);
if (uFolder == null) {
log(lvl, "resourceList: not found: %s", folder);
return files;
}
try {
uFolder = new URL(uFolder.toExternalForm().replaceAll(" ", "%20"));
} catch (Exception ex) {
}
URL uContentList = clsRef.getResource(folder + "/" + fpContent);
if (uContentList != null) {
return doResourceListWithList(folder, files, filter);
}
File fFolder = null;
try {
fFolder = new File(uFolder.toURI());
log(lvl, "resourceList: having folder: %s", fFolder);
String sFolder = FileManager.normalizeAbsolute(fFolder.getPath(), false);
if (":".equals(sFolder.substring(2, 3))) {
sFolder = sFolder.substring(1);
}
files.add(sFolder);
files = doResourceListFolder(new File(sFolder), files, filter);
files.remove(0);
return files;
} catch (Exception ex) {
if (!"jar".equals(uFolder.getProtocol())) {
log(lvl, "resourceList:\n%s", folder);
log(-1, "resourceList: URL neither folder nor jar:\n%s", ex);
return null;
}
}
String[] parts = uFolder.getPath().split("!");
if (parts.length < 2 || !parts[0].startsWith("file:")) {
log(lvl, "resourceList:\n%s", folder);
log(-1, "resourceList: not a valid jar URL: " + uFolder.getPath());
return null;
}
String fpFolder = parts[1];
log(lvl, "resourceList: having jar: %s", uFolder);
return doResourceListJar(uFolder, fpFolder, files, filter);
}
/**
* write the list as it is produced by calling extractResourcesToFolder to the given file with system line
* separator<br>
* non-compact format: every file with full path
*
* @param folder path of the subtree relative to root with leading /
* @param target the file to write the list (if null, only list - no file)
* @param filter implementation of interface FilenameFilter or null for no filtering
* @return success
*/
public String[] resourceListAsFile(String folder, File target, FilenameFilter filter) {
String content = resourceListAsString(folder, filter);
if (content == null) {
log(-1, "resourceListAsFile: did not work: %s", folder);
return null;
}
if (target != null) {
try {
FileManager.deleteFileOrFolder(target.getAbsolutePath());
target.getParentFile().mkdirs();
PrintWriter aPW = new PrintWriter(target);
aPW.write(content);
aPW.close();
} catch (Exception ex) {
log(-1, "resourceListAsFile: %s:\n%s", target, ex);
}
}
return content.split(System.getProperty("line.separator"));
}
/**
* write the list as it is produced by calling extractResourcesToFolder to the given file with system line
* separator<br>
* compact sikulixcontent format
*
* @param folder path of the subtree relative to root with leading /
* @param targetFolder the folder where to store the file sikulixcontent (if null, only list - no export)
* @param filter implementation of interface FilenameFilter or null for no filtering
* @return success
*/
public String[] resourceListAsSikulixContent(String folder, File targetFolder, FilenameFilter filter) {
List<String> contentList = resourceList(folder, filter);
if (contentList == null) {
log(-1, "resourceListAsSikulixContent: did not work: %s", folder);
return null;
}
File target = null;
String arrString[] = new String[contentList.size()];
try {
PrintWriter aPW = null;
if (targetFolder != null) {
target = new File(targetFolder, fpContent);
FileManager.deleteFileOrFolder(target);
target.getParentFile().mkdirs();
aPW = new PrintWriter(target);
}
int n = 0;
for (String line : contentList) {
arrString[n++] = line;
if (targetFolder != null) {
aPW.println(line);
}
}
if (targetFolder != null) {
aPW.close();
}
} catch (Exception ex) {
log(-1, "resourceListAsFile: %s:\n%s", target, ex);
}
return arrString;
}
/**
* write the list as it is produced by calling extractResourcesToFolder to the given file with system line
* separator<br>
* compact sikulixcontent format
*
* @param aJar absolute path to an existing jar or a string identifying the jar on classpath (no leading /)
* @param folder path of the subtree relative to root with leading /
* @param targetFolder the folder where to store the file sikulixcontent (if null, only list - no export)
* @param filter implementation of interface FilenameFilter or null for no filtering
* @return success
*/
public String[] resourceListAsSikulixContentFromJar(String aJar, String folder, File targetFolder, FilenameFilter filter) {
List<String> contentList = extractResourcesToFolderFromJar(aJar, folder, null, filter);
if (contentList == null || contentList.size() == 0) {
log(-1, "resourceListAsSikulixContentFromJar: did not work: %s", folder);
return null;
}
File target = null;
String arrString[] = new String[contentList.size()];
try {
PrintWriter aPW = null;
if (targetFolder != null) {
target = new File(targetFolder, fpContent);
FileManager.deleteFileOrFolder(target);
target.getParentFile().mkdirs();
aPW = new PrintWriter(target);
}
int n = 0;
for (String line : contentList) {
arrString[n++] = line;
if (targetFolder != null) {
aPW.println(line);
}
}
if (targetFolder != null) {
aPW.close();
}
} catch (Exception ex) {
log(-1, "resourceListAsFile: %s:\n%s", target, ex);
}
return arrString;
}
/**
* write the list produced by calling extractResourcesToFolder to the returned string with system line separator<br>
* non-compact format: every file with full path
*
* @param folder path of the subtree relative to root with leading /
* @param filter implementation of interface FilenameFilter or null for no filtering
* @return the resulting string
*/
public String resourceListAsString(String folder, FilenameFilter filter) {
return resourceListAsString(folder, filter, null);
}
/**
* write the list produced by calling extractResourcesToFolder to the returned string with given separator<br>
* non-compact format: every file with full path
*
* @param folder path of the subtree relative to root with leading /
* @param filter implementation of interface FilenameFilter or null for no filtering
* @param separator to be used to separate the entries
* @return the resulting string
*/
public String resourceListAsString(String folder, FilenameFilter filter, String separator) {
List<String> aList = resourceList(folder, filter);
if (aList == null) {
return null;
}
if (separator == null) {
separator = System.getProperty("line.separator");
}
String out = "";
String subFolder = "";
if (aList != null && aList.size() > 0) {
for (String eFile : aList) {
if (eFile == null) {
continue;
}
if (eFile.endsWith("/")) {
subFolder = eFile.substring(0, eFile.length() - 1);
continue;
}
if (!subFolder.isEmpty()) {
eFile = new File(subFolder, eFile).getPath();
}
out += eFile.replace("\\", "/") + separator;
}
}
return out;
}
private List<String> doResourceListFolder(File fFolder, List<String> files, FilenameFilter filter) {
int localLevel = testing ? lvl : lvl + 1;
String subFolder = "";
if (fFolder.isDirectory()) {
if (!FileManager.pathEquals(fFolder.getPath(), files.get(0))) {
subFolder = fFolder.getPath().substring(files.get(0).length() + 1).replace("\\", "/") + "/";
if (filter != null && !filter.accept(new File(files.get(0), subFolder), "")) {
return files;
}
} else {
logp(localLevel, "scanning folder:\n%s", fFolder);
subFolder = "/";
files.add(subFolder);
}
String[] subList = fFolder.list();
for (String entry : subList) {
File fEntry = new File(fFolder, entry);
if (fEntry.isDirectory()) {
files.add(fEntry.getAbsolutePath().substring(1 + files.get(0).length()).replace("\\", "/") + "/");
doResourceListFolder(fEntry, files, filter);
files.add(subFolder);
} else {
if (filter != null && !filter.accept(fFolder, entry)) {
continue;
}
logp(localLevel, "from %s adding: %s", (subFolder.isEmpty() ? "." : subFolder), entry);
files.add(fEntry.getAbsolutePath().substring(1 + fFolder.getPath().length()));
}
}
}
return files;
}
private List<String> doResourceListWithList(String folder, List<String> files, FilenameFilter filter) {
String content = extractResourceToString(folder, fpContent, "");
String[] contentList = content.split(content.indexOf("\r") != -1 ? "\r\n" : "\n");
if (filter == null) {
files.addAll(Arrays.asList(contentList));
} else {
for (String fpFile : contentList) {
if (filter.accept(new File(fpFile), "")) {
files.add(fpFile);
}
}
}
return files;
}
private List<String> doResourceListJar(URL uJar, String fpResource, List<String> files, FilenameFilter filter) {
ZipInputStream zJar;
String fpJar = uJar.getPath().split("!")[0];
int localLevel = testing ? lvl : lvl + 1;
String fileSep = "/";
if (!fpJar.endsWith(".jar")) {
return files;
}
logp(localLevel, "scanning jar:\n%s", uJar);
fpResource = (fpResource.startsWith("/") ? fpResource.substring(1) : fpResource) + "/";
File fFolder = new File(fpResource);
File fSubFolder = null;
ZipEntry zEntry;
String subFolder = "";
boolean skip = false;
try {
zJar = new ZipInputStream(new URL(fpJar).openStream());
while ((zEntry = zJar.getNextEntry()) != null) {
if (zEntry.getName().endsWith("/")) {
continue;
}
String zePath = zEntry.getName();
if (zePath.startsWith(fpResource)) {
// if (fpResource.length() == zePath.length()) {
// files.add(zePath);
// return files;
// }
String zeName = zePath.substring(fpResource.length());
int nSep = zeName.lastIndexOf(fileSep);
String zefName = zeName.substring(nSep + 1, zeName.length());
String zeSub = "";
if (nSep > -1) {
zeSub = zeName.substring(0, nSep + 1);
if (!subFolder.equals(zeSub)) {
subFolder = zeSub;
fSubFolder = new File(fFolder, subFolder);
skip = false;
if (filter != null && !filter.accept(fSubFolder, "")) {
skip = true;
continue;
}
files.add(zeSub);
}
if (skip) {
continue;
}
} else {
if (!subFolder.isEmpty()) {
subFolder = "";
fSubFolder = fFolder;
files.add("/");
}
}
if (filter != null && !filter.accept(fSubFolder, zefName)) {
continue;
}
files.add(zefName);
logp(localLevel, "from %s adding: %s", (zeSub.isEmpty() ? "." : zeSub), zefName);
}
}
} catch (Exception ex) {
log(-1, "doResourceListJar: %s", ex);
return files;
}
return files;
}
private boolean copyFromJarToFolderWithList(URL uJar, String fpRessource, List<String> files, File fFolder) {
if (files == null || files.isEmpty()) {
log(lvl, "copyFromJarToFolderWithList: list of files is empty");
return false;
}
String fpJar = uJar.getPath().split("!")[0];
if (!fpJar.endsWith(".jar")) {
return false;
}
int localLevel = testing ? lvl : lvl + 1;
logp(localLevel, "scanning jar:\n%s", uJar);
fpRessource = fpRessource.startsWith("/") ? fpRessource.substring(1) : fpRessource;
String subFolder = "";
int maxFiles = files.size() - 1;
int nFiles = 0;
ZipEntry zEntry;
ZipInputStream zJar;
String zPath;
int prefix = fpRessource.length();
fpRessource += !fpRessource.isEmpty() ? "/" : "";
String current = "/";
boolean shouldStop = false;
try {
zJar = new ZipInputStream(new URL(fpJar).openStream());
while ((zEntry = zJar.getNextEntry()) != null) {
zPath = zEntry.getName();
if (zPath.endsWith("/")) {
continue;
}
while (current.endsWith("/")) {
if (nFiles > maxFiles) {
shouldStop = true;
break;
}
subFolder = current.length() == 1 ? "" : current;
current = files.get(nFiles++);
if (!current.endsWith("/")) {
current = fpRessource + subFolder + current;
break;
}
}
if (shouldStop) {
break;
}
if (zPath.startsWith(current)) {
if (zPath.length() == fpRessource.length() - 1) {
log(-1, "extractResourcesToFolderFromJar: only ressource folders allowed - use filter");
return false;
}
logp(localLevel, "copying: %s", zPath);
File out = new File(fFolder, zPath.substring(prefix));
if (!out.getParentFile().exists()) {
out.getParentFile().mkdirs();
}
FileOutputStream aFileOS = new FileOutputStream(out);
copy(zJar, aFileOS);
aFileOS.close();
if (nFiles > maxFiles) {
break;
}
current = files.get(nFiles++);
if (!current.endsWith("/")) {
current = fpRessource + subFolder + current;
}
}
}
zJar.close();
} catch (Exception ex) {
log(-1, "doResourceListJar: %s", ex);
return false;
}
return true;
}
private void copy(InputStream in, OutputStream out) throws IOException {
byte[] tmp = new byte[8192];
int len;
while (true) {
len = in.read(tmp);
if (len <= 0) {
break;
}
out.write(tmp, 0, len);
}
out.flush();
}
private byte[] copy(InputStream inputStream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toByteArray();
}
public class oneFileFilter implements FilenameFilter {
String aFile;
public oneFileFilter(String aFileGiven) {
aFile = aFileGiven;
}
@Override
public boolean accept(File dir, String name) {
if (name.contains(aFile)) {
return true;
}
return false;
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="classpath handling">
private void storeClassPath() {
//TODO Java9
URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
classPath = Arrays.asList(sysLoader.getURLs());
}
/**
* print the current classpath entries to sysout
*/
public void dumpClassPath() {
dumpClassPath(null);
}
/**
* print the current classpath entries to sysout whose path name contain the given string
*
* @param filter the fileter string
*/
public void dumpClassPath(String filter) {
filter = filter == null ? "" : filter;
logp("*** classpath dump %s", filter);
storeClassPath();
String sEntry;
filter = filter.toUpperCase();
int n = 0;
for (URL uEntry : classPath) {
sEntry = uEntry.getPath();
if (!filter.isEmpty()) {
if (!sEntry.toUpperCase().contains(filter)) {
n++;
continue;
}
}
logp("%3d: %s", n, sEntry);
n++;
}
logp("*** classpath dump end");
}
/**
* check whether a classpath entry contains the given identifying string, stops on first match
*
* @param artefact the identifying string
* @return the absolute path of the entry found - null if not found
*/
private String isOnClasspath(String artefact, boolean isJar) {
artefact = FileManager.slashify(artefact, false);
String cpe = null;
if (classPath.isEmpty()) {
storeClassPath();
}
for (URL entry : classPath) {
String sEntry = FileManager.slashify(new File(entry.getPath()).getPath(), false);
if (sEntry.contains(artefact)) {
if (isJar) {
if (!sEntry.endsWith(".jar")) {
continue;
}
if (!new File(sEntry).getName().contains(artefact)) {
continue;
}
if (new File(sEntry).getName().contains("4" + artefact)) {
continue;
}
}
cpe = new File(entry.getPath()).getPath();
break;
}
}
return cpe;
}
public String isJarOnClasspath(String artefact) {
return isOnClasspath(artefact, true);
}
public String isOnClasspath(String artefact) {
return isOnClasspath(artefact, false);
}
public URL fromClasspath(String artefact) {
artefact = FileManager.slashify(artefact, false).toUpperCase();
URL cpe = null;
if (classPath.isEmpty()) {
storeClassPath();
}
for (URL entry : classPath) {
String sEntry = FileManager.slashify(new File(entry.getPath()).getPath(), false);
if (sEntry.toUpperCase().contains(artefact)) {
return entry;
}
}
return cpe;
}
/**
* check wether a the given URL is on classpath
*
* @param path URL to look for
* @return true if found else otherwise
*/
public boolean isOnClasspath(URL path) {
if (classPath.isEmpty()) {
storeClassPath();
}
for (URL entry : classPath) {
if (new File(path.getPath()).equals(new File(entry.getPath()))) {
return true;
}
}
return false;
}
/**
* adds the given folder or jar to the end of the current classpath
*
* @param jarOrFolder absolute path to a folder or jar
* @return success
*/
public boolean addToClasspath(String jarOrFolder) {
URL uJarOrFolder = FileManager.makeURL(jarOrFolder);
if (!new File(jarOrFolder).exists()) {
log(-1, "addToClasspath: does not exist - not added:\n%s", jarOrFolder);
return false;
}
if (isOnClasspath(uJarOrFolder)) {
return true;
}
log(lvl, "addToClasspath:\n%s", uJarOrFolder);
Method method;
URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;
try {
method = sysclass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(sysLoader, new Object[]{uJarOrFolder});
} catch (Exception ex) {
log(-1, "Did not work: %s", ex.getMessage());
return false;
}
storeClassPath();
return true;
}
public File asExtension(String fpJar) {
File fJarFound = new File(FileManager.normalizeAbsolute(fpJar, false));
if (!fJarFound.exists()) {
String fpCPEntry = runTime.isOnClasspath(fJarFound.getName());
if (fpCPEntry == null) {
fJarFound = new File(runTime.fSikulixExtensions, fpJar);
if (!fJarFound.exists()) {
fJarFound = new File(runTime.fSikulixLib, fpJar);
if (!fJarFound.exists()) {
fJarFound = null;
}
}
} else {
fJarFound = new File(fpCPEntry, fJarFound.getName());
}
} else {
return null;
}
return fJarFound;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="system enviroment">
/**
* print the current java system properties key-value pairs sorted by key
*/
public void dumpSysProps() {
dumpSysProps(null);
}
/**
* print the current java system properties key-value pairs sorted by key but only keys containing filter
*
* @param filter the filter string
*/
public void dumpSysProps(String filter) {
filter = filter == null ? "" : filter;
logp("*** system properties dump " + filter);
Properties sysProps = System.getProperties();
ArrayList<String> keysProp = new ArrayList<String>();
Integer nL = 0;
String entry;
for (Object e : sysProps.keySet()) {
entry = (String) e;
if (entry.length() > nL) {
nL = entry.length();
}
if (filter.isEmpty() || !filter.isEmpty() && entry.contains(filter)) {
keysProp.add(entry);
}
}
Collections.sort(keysProp);
String form = "%-" + nL.toString() + "s = %s";
for (Object e : keysProp) {
logp(form, e, sysProps.get(e));
}
logp("*** system properties dump end" + filter);
}
/**
* checks, whether Java runs with a valid GraphicsEnvironment (usually means real screens connected)
*
* @return false if Java thinks it has access to screen(s), true otherwise
*/
public boolean isHeadless() {
return GraphicsEnvironment.isHeadless();
}
public boolean isMultiMonitor() {
return nMonitors > 1;
}
public Rectangle getMonitor(int n) {
if (isHeadless()) {
return new Rectangle(0, 0, 1, 1);
}
if (null == monitorBounds) {
return null;
}
n = (n < 0 || n >= nMonitors) ? mainMonitor : n;
return monitorBounds[n];
}
public Rectangle getAllMonitors() {
if (isHeadless()) {
return new Rectangle(0, 0, 1, 1);
}
return rAllMonitors;
}
public Rectangle hasPoint(Point aPoint) {
if (isHeadless()) {
return new Rectangle(0, 0, 1, 1);
}
for (Rectangle rMon : monitorBounds) {
if (rMon.contains(aPoint)) {
return rMon;
}
}
return null;
}
public Rectangle hasRectangle(Rectangle aRect) {
if (isHeadless()) {
return new Rectangle(0, 0, 1, 1);
}
return hasPoint(aRect.getLocation());
}
public GraphicsDevice getGraphicsDevice(int id) {
return gdevs[id];
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="runcmd">
/**
* run a system command finally using Java::Runtime.getRuntime().exec(args) and waiting for completion
*
* @param cmd the command as it would be given on command line, quoting is preserved
* @return the output produced by the command (sysout [+ "*** error ***" + syserr] if the syserr part is present, the
* command might have failed
*/
public String runcmd(String cmd) {
return runcmd(new String[]{cmd});
}
/**
* run a system command finally using Java::Runtime.getRuntime().exec(args) and waiting for completion
*
* @param args the command as it would be given on command line splitted into the space devided parts, first part is
* the command, the rest are parameters and their values
* @return the output produced by the command (sysout [+ "*** error ***" + syserr] if the syserr part is present, the
* command might have failed
*/
public String runcmd(String args[]) {
if (args.length == 0) {
return "";
}
boolean silent = false;
if (args.length == 1) {
String separator = "\"";
ArrayList<String> argsx = new ArrayList<String>();
StringTokenizer toks;
String tok;
String cmd = args[0];
if (Settings.isWindows()) {
cmd = cmd.replaceAll("\\\\ ", "%20;");
}
toks = new StringTokenizer(cmd);
while (toks.hasMoreTokens()) {
tok = toks.nextToken(" ");
if (tok.length() == 0) {
continue;
}
if (separator.equals(tok)) {
continue;
}
if (tok.startsWith(separator)) {
if (tok.endsWith(separator)) {
tok = tok.substring(1, tok.length() - 1);
} else {
tok = tok.substring(1);
tok += toks.nextToken(separator);
}
}
argsx.add(tok.replaceAll("%20;", " "));
}
args = argsx.toArray(new String[0]);
}
if (args[0].startsWith("!")) {
silent = true;
args[0] = args[0].substring(1);
}
if (args[0].startsWith("#")) {
String pgm = args[0].substring(1);
args[0] = (new File(pgm)).getAbsolutePath();
runcmd(new String[]{"chmod", "ugo+x", args[0]});
}
String result = "";
String error = runCmdError + NL;
String errorOut = "";
boolean hasError = false;
int retVal;
try {
if (!silent) {
if (lvl <= Debug.getDebugLevel()) {
log(lvl, Sikulix.arrayToString(args));
} else {
Debug.info("runcmd: " + Sikulix.arrayToString(args));
}
}
Process process = Runtime.getRuntime().exec(args);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = stdInput.readLine()) != null) {
if (!s.isEmpty()) {
result += s + NL;
}
}
while ((s = stdError.readLine()) != null) {
if (!s.isEmpty()) {
errorOut += s + NL;
}
}
if (!errorOut.isEmpty()) {
error = error + errorOut;
hasError = true;
}
process.waitFor();
retVal = process.exitValue();
process.destroy();
} catch (Exception e) {
log(-1, "fatal error: " + e);
result = String.format(error + "%s", e);
retVal = 9999;
hasError = true;
}
if (hasError) {
result += error;
}
lastResult = result;
return String.format("%d%s%s", retVal, NL, result);
}
public String getLastCommandResult() {
return lastResult;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="args handling for scriptrunner">
private String[] args = new String[0];
private String[] sargs = new String[0];
public void setArgs(String[] args, String[] sargs) {
this.args = args;
this.sargs = sargs;
}
public String[] getSikuliArgs() {
return sargs;
}
public String[] getArgs() {
return args;
}
public void printArgs() {
if (Debug.getDebugLevel() < lvl) {
return;
}
String[] xargs = getSikuliArgs();
if (xargs.length > 0) {
Debug.log(lvl, "--- Sikuli parameters ---");
for (int i = 0; i < xargs.length; i++) {
Debug.log(lvl, "%d: %s", i + 1, xargs[i]);
}
}
xargs = getArgs();
if (xargs.length > 0) {
Debug.log(lvl, "--- User parameters ---");
for (int i = 0; i < xargs.length; i++) {
Debug.log(lvl, "%d: %s", i + 1, xargs[i]);
}
}
}
public static int checkArgs(String[] args, Type typ) {
int debugLevel = -99;
boolean runningScripts = false;
List<String> options = new ArrayList<String>();
options.addAll(Arrays.asList(args));
for (int n = 0; n < options.size(); n++) {
String opt = options.get(n);
if ("nodebug".equals(opt)) {
return -2;
}
if (Type.IDE.equals(typ) && "-s".equals(opt.toLowerCase())) {
return -3;
}
if (!opt.startsWith("-")) {
continue;
}
if (opt.startsWith("-d")) {
debugLevel = -1;
try {
debugLevel = n + 1 == options.size() ? -1 : Integer.decode(options.get(n + 1));
} catch (Exception ex) {
debugLevel = -1;
}
if (debugLevel > -1) {
Debug.on(debugLevel);
}
} else if (opt.startsWith("-r") || opt.startsWith("-t")
|| opt.startsWith("-s") || opt.startsWith("-i")) {
runningScripts = true;
}
}
if (runningScripts) {
return 999;
}
return debugLevel;
}
//</editor-fold>
}