/*- * Copyright (c) 2014 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.jython; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.dawb.common.util.eclipse.BundleUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JythonPath { private static Logger logger = LoggerFactory.getLogger(JythonPath.class); private static final String GIT_REPO_ENDING = ".git"; private static final String GIT_SUFFIX = "_git"; private static final String JYTHON_BUNDLE = "uk.ac.diamond.jython"; private static final String JYTHON_BUNDLE_LOC = JYTHON_BUNDLE + ".location"; private static final String JYTHON_EXEC= "jython.jar"; private static final String JYTHON_VERSION = "2.7"; private static final String JYTHON_DIR = "jython" + JYTHON_VERSION; private static final String SCISOFTPY = "uk.ac.diamond.scisoft.python"; /* * Lists of Jars we want to/don't want to include */ private static final String[] blackListedJarDirs = { "uk.ac.gda.libs", "ch.qos.logback.eclipse", "ch.qos.logback.beagle", "org.dawb.workbench.jmx", GIT_REPO_ENDING, JYTHON_DIR, "org.dawnsci.persistence.test" // Required for I11 LDE script (we don't want the tests!) }; private static final String[] requiredJars = { "org.python.pydev", "cbflib-0.9", "org.apache.commons.codec", "org.apache.commons.math3", // math3 only now "uk.ac.diamond.CBFlib", "uk.ac.diamond.jama", "com.googlecode.efficient-java-matrix-library.core", "org.ddogleg", "org.apache.commons.lang", "org.eclipse.january", "org.eclipse.dawnsci.analysis", // Includes api, dataset, tree, etc "org.eclipse.dawnsci.nexus", // required for loading to work in client started from IDE "org.eclipse.dawnsci.plotting.api", "uk.ac.diamond.scisoft.analysis", "uk.ac.diamond.scisoft.diffraction.powder", "uk.ac.diamond.scisoft.python", "uk.ac.diamond.scisoft.spectroscopy", "uk.ac.gda.common", "org.eclipse.dawnsci.hdf5", // Fix to http://jira.diamond.ac.uk/browse/SCI-1467 "slf4j.api", "jcl.over.slf4j", "log4j.over.slf4j", "ch.qos.logback.core", "ch.qos.logback.classic", "com.springsource.org.apache.commons", "com.springsource.javax.media.jai.core", "com.springsource.javax.media.jai.codec", "JTransforms", "jai_imageio", "it.tidalwave.imageio.raw", "javax.vecmath", "uk.ac.diamond.org.apache.ws.commons.util", "uk.ac.diamond.org.apache.xmlrpc.client", "uk.ac.diamond.org.apache.xmlrpc.common", "uk.ac.diamond.org.apache.xmlrpc.server", "com.thoughtworks.xstream", "uk.ac.diamond.org.jscience4", "org.eclipse.equinox.common", // Required for IRemotePlottingSystem "org.dawnsci.boofcv", // Required for running boofcv image processing in jython "org.boofcv.feature", "org.boofcv.geo", "org.boofcv.ip", "org.boofcv.sfm", "org.ddogleg", "org.dawnsci.persistence" // Required for I11 LDE script }; /* * Plugins we want */ private final static String[] pluginKeys = { "org.eclipse.january", "org.eclipse.dawnsci.hdf5", // required for loading to work in client started from IDE "org.eclipse.dawnsci.analysis", // includes api, dataset, tree, etc "org.eclipse.dawnsci.nexus", // required for loading to work in client started from IDE "org.eclipse.dawnsci.plotting", // required to expose IRemotePlottingSystem to Jython "uk.ac.diamond.scisoft.analysis", "uk.ac.diamond.scisoft.diffraction.powder", "uk.ac.diamond.scisoft.python", "uk.ac.diamond.CBFlib", "uk.ac.gda.common", "org.dawnsci.boofcv", //required for boofcv services "org.ddogleg", "hdf.hdf5lib", "hdf.object", // used in dawnsci.hdf.HDF5Utils as well as older Hierarchical stuff "org.dawnsci.persistence" // Required for I11 LDE script }; /** * Provides location of plugin files; behaviour depends whether we're running in eclipse * @param isRunningInEclipse Boolean, true if running in eclipse * @return Directory where plugins live (defined as parent of current bundle) */ public static File getPluginsDirectory(boolean isRunningInEclipse) { try { File scisoftParent = BundleUtils.getBundleLocation(SCISOFTPY).getParentFile(); if (isRunningInEclipse) { scisoftParent = scisoftParent.getParentFile(); } //Need to include a logging statement return scisoftParent; } catch (Exception e) { logger.error("Could not find Scisoft Python plugin", e); } return null; } /** * Gets the interpreter directory using the bundle location * @return directory path * @throws Exception when JYTHON_BUNDLE_LOC is not set (and no Jython bundle found) */ public static File getInterpreterDirectory(boolean isRunningInEclipse) throws Exception { File jyBundleLoc = null; try { jyBundleLoc = BundleUtils.getBundleLocation(JYTHON_BUNDLE); } catch (Exception ignored) { } if (jyBundleLoc == null) { if (System.getProperty(JYTHON_BUNDLE_LOC)==null) throw new Exception("Please set the property '" + JYTHON_BUNDLE_LOC + "' for this test to work!"); jyBundleLoc = new File(System.getProperty(JYTHON_BUNDLE_LOC)); } jyBundleLoc = new File(jyBundleLoc, JYTHON_DIR); // Test whether we're running in if (!isRunningInEclipse && jyBundleLoc.getAbsolutePath().contains(GIT_REPO_ENDING)) { logger.error("Using jython from git, but -Drun.in.eclipse set false. This will cause errors."); return null; } logger.info("Jython bundle found at: {}", jyBundleLoc); return jyBundleLoc; } /** * Returns a set containing all of the plugins/jars found in the given * directories which are in the requiredJars, pluginKeys, extraPlugins and not * in the blackListedJarDirs arrays. * @param pluginsDir * @param isRunningInEclipse * @return jyPaths Set containing all of the required plugins */ public static final Set<String> assembleJyPaths(File pluginsDir, boolean isRunningInEclipse) { return assembleJyPaths(pluginsDir, null, isRunningInEclipse); } /** * Returns a set containing all of the plugins/jars found in the given * directories which are in the requiredJars, pluginKeys, extraPlugins and not * in the blackListedJarDirs arrays. * @param pluginsDir * @param extras * @param isRunningInEclipse * @return jyPaths Set containing all of the required plugins */ public static final Set<String> assembleJyPaths(File pluginsDir, Collection<String> extras, boolean isRunningInEclipse) { final Set<String> jyPaths = new HashSet<String>(); //Find third party jar files & add them all final List<File> thirdPartyJars = findJars(pluginsDir, extras); for (File jar : thirdPartyJars) { if (jyPaths.add(jar.getAbsolutePath())) { logger.debug("Adding jar file to jython path: {} ", jar.getAbsolutePath()); } } //Find all the plugin directories List<File> allPluginDirs = findDirs(pluginsDir, extras, isRunningInEclipse); //Find other plugin directories. Where searched depends on if running in eclipse if (isRunningInEclipse) { //Locate wsdir (w/o GIT_SUFFIX) File wsDir = pluginsDir; if (!new File(wsDir, "tp").isDirectory()) { String ws = wsDir.getName(); int i = ws.indexOf(GIT_SUFFIX); if (i >= 0) { wsDir = new File(wsDir.getParentFile(), ws.substring(0, i)); } } //Add dirs inside the wsDir/plugins directory final File wsPluginsDir = new File(wsDir, "plugins"); if (wsPluginsDir.isDirectory()) { allPluginDirs.addAll(findDirs(wsPluginsDir, extras, isRunningInEclipse)); } //Add jars inside the wsdir/plugins directory wsDir = new File(wsDir, "tp"); if (wsDir.isDirectory()) { wsDir = new File(wsDir, "plugins"); final List<File> tJars = findJars(wsDir, extras); for (File file : tJars) { if (jyPaths.add(file.getAbsolutePath())) { logger.debug("Adding jar file to jython path: {} ", file.getAbsolutePath()); } } } //Add all plugin directories & jars contained therein for (File dir: allPluginDirs){ File binDir = new File(dir,"bin"); if (binDir.isDirectory()) { String binDirPath = binDir.getAbsolutePath(); if (jyPaths.add(binDirPath)) { logger.debug("Adding directory to jython path: {}", binDirPath); } } final List<File> tJars = findJars(dir, extras); for (File jar : tJars) { if (jyPaths.add(jar.getAbsolutePath())) { logger.debug("Adding jar file to jython path: {} ", jar.getAbsolutePath()); } } } } else { //Only add directories to pyPaths for (File dir: allPluginDirs) { String dirPath = dir.getAbsolutePath(); if (jyPaths.add(dirPath)) { logger.debug("Adding directory to jython path: {}", dirPath); } } } return jyPaths; } /** * Recursively search through a given directory to locate all jar files provided * they are in the requiredJars/extraPlugins lists * @param directory location searched for jar files * @return List of jar files which will be added to the path */ private static final List<File> findJars(File directory, Collection<String> extraPlugins) { final List<File> jarFiles = new ArrayList<File>(); if (directory.isDirectory()) { for (File file : directory.listFiles()) { final String name = file.getName(); //If the file is a jar, then add it if (name.endsWith(".jar")) { if (isRequired(file, requiredJars, extraPlugins)) { jarFiles.add(file); } } else if (file.isDirectory() && !isRequired(file, blackListedJarDirs)) { jarFiles.addAll(findJars(file, extraPlugins)); } } } return jarFiles; } /** * Method returns path to plugin directories (behaviour depends on whether in eclipse * @param directory Search location * @param isRunningInEclipse Boolean, true if running in eclipse * @return list of directories */ public static List<File> findDirs(File directory, Collection<String> extras, boolean isRunningInEclipse) { final List<File> plugins = new ArrayList<File>(); // TODO This could be shortened code-wise (move for loop outside if), but that might be slower in execution if (isRunningInEclipse) { //Look in git repos for plugin parents in given lists for (File file : directory.listFiles()) { if (file.isDirectory()) { String fileName = file.getName(); if (fileName.endsWith(GIT_REPO_ENDING)) { //Look in plugin parent for actual plugin directories plugins.addAll(findDirs(file, extras, false)); } } } } else { //Look in directory for plugin names in given lists for (File file : directory.listFiles()) { if (file.isDirectory()) { if (isRequired(file, pluginKeys, extras)) { logger.debug("Found plugin directory {}", file); plugins.add(file); } } } } //Return all the directories we found return plugins; } /** * Check whether a file is in a given list * @param file Filename to search for * @param keys List to search against * @return Boolean, true if file is in list */ private static boolean isRequired(File file, String[] keys) { return isRequired(file, keys, null); } /** * Check whether a file is in given lists * @param file Filename to search for * @param keys List to search against * @return Boolean, true if file is in list */ private static boolean isRequired(File file, String[] keys, Collection<String> extraKeys) { String filename = file.getName(); // logger.debug("Jar/dir found: {}", filename); for (String key : keys) { if (filename.startsWith(key)) return true; } if (extraKeys != null) { for (String key : extraKeys) { if (filename.startsWith(key)) return true; } } return false; } /** * Returns name of Jython executable. * @return JYTHON_EXEC */ public static String getJythonExecutableName() { return JYTHON_EXEC; } public static String getJythonVersion() { return JYTHON_VERSION; } }