package jetbrains.mps.build.ant; /*Generated by MPS */ import java.util.Collection; import java.io.File; import org.apache.tools.ant.Project; import java.util.List; import java.util.ArrayList; import org.apache.tools.ant.BuildException; import org.jetbrains.annotations.NotNull; import java.net.URL; import java.net.URLDecoder; import java.net.MalformedURLException; import java.io.UnsupportedEncodingException; import java.util.Set; public class MPSClasspathUtil { private static final String FILE = "file"; private static final String JAR = "jar"; private static final String JAR_DELIMITER = "!"; private static final String PROTOCOL_DELIMITER = ":"; private static final String[] CLASSPATH = new String[]{"trove4j.jar", "mps-collections.jar", "mps-closures.jar", "mps-tuples.jar", "mps-openapi.jar", "mps-core.jar", "mps-tool.jar", "mps-behavior-api.jar", "mps-behavior-runtime.jar", "mps-logging.jar", "mps-annotations.jar", "mps-boot-util.jar"}; private static final String[] FORK_CLASSPATH = new String[]{"jdom.jar", "log4j.jar", "ecj-4.6.2.jar", "xstream-1.4.8.jar", "asm4-all.jar", "asm-all.jar", "diffutils-1.2.1.jar", "junit-4.12.jar", "javac2.jar"}; public static Collection<File> buildClasspath(Project antProject, File mpsHomeArg, boolean fork) { List<File> homeFolders = new ArrayList<File>(); boolean foundMpsHome = false; // if there is mps_home either in property or passed to the task as attribute if (mpsHomeArg == null || !(mpsHomeArg.isDirectory())) { homeFolders.add(getAntJARRelativeHome()); mpsHomeArg = resolveMPSHome(antProject, false); } if (mpsHomeArg != null) { File lib = new File(mpsHomeArg, "lib"); if (lib.isDirectory()) { foundMpsHome = true; homeFolders.add(lib); } } // if there is no mps_home if (!(foundMpsHome)) { homeFolders.add(getAntJARRelativeHome()); homeFolders.addAll(getClassPathRootsFromDependencies(antProject)); } List<File> result = new ArrayList<File>(); if (fork) { MPSClasspathUtil.collectClasspath(FORK_CLASSPATH, homeFolders, result); } MPSClasspathUtil.collectClasspath(CLASSPATH, homeFolders, result); return result; } public static List<File> getHomeFolders(Project antProject, File mpsHomeArg) { List<File> homeFolders = new ArrayList<File>(); if (mpsHomeArg == null || !(mpsHomeArg.isDirectory())) { homeFolders.add(getAntJARRelativeHome()); mpsHomeArg = resolveMPSHome(antProject, false); } if (mpsHomeArg != null) { File lib = new File(mpsHomeArg, "lib"); if (lib.isDirectory()) { homeFolders.add(lib); } } if (homeFolders.isEmpty()) { homeFolders.add(getAntJARRelativeHome()); } return homeFolders; } private static void collectClasspath(String[] fileNames, List<File> homeFolders, List<File> result) { for (String name : fileNames) { File file = null; for (File home : homeFolders) { File f = new File(home, name); if (f.isFile()) { file = f; break; } } if (file == null) { throw new BuildException("cannot find `" + name + "' in " + homeFolders.toString()); } else { result.add(file); } } } public static File resolveMPSHome(Project antProject, boolean failOtherwise) { String mpsHomePath = antProject.getProperty("mps.home"); if ((mpsHomePath == null || mpsHomePath.length() == 0)) { mpsHomePath = antProject.getProperty("mps_home"); } if (mpsHomePath == null || !(antProject.resolveFile(mpsHomePath).exists())) { if (failOtherwise) { throw new BuildException("Path to mps home expected. Specify mps.home property or mpsHome attribute."); } else { return null; } } return antProject.resolveFile(mpsHomePath); } private static File getAntJARRelativeHome() { String containingJar = getAntMPSJar(); if (!(containingJar.toLowerCase().endsWith(".jar"))) { throw new BuildException("cannot detect jar location: got `" + containingJar + "'"); } File current = new File(containingJar); for (int i = 0; i < 3; i++) { current = current.getParentFile(); if (current == null) { throw new BuildException("cannot detect jar location, no parent: got `" + containingJar + "'"); } if (new File(current, "mps-core.jar").isFile()) { return current; } } throw new BuildException("cannot detect jar location, no mps-core.jar `" + containingJar + "'"); } @NotNull private static String getAntMPSJar() { Class aClass = MPSClasspathUtil.class; return getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class"); } /** * Attempts to detect classpath entry which contains given resource */ @NotNull private static String getResourceRoot(Class context, String path) { URL url = context.getResource(path); if (url == null) { url = ClassLoader.getSystemResource(path.substring(1)); } if (url == null) { throw new BuildException("cannot detect jar location; no resource `" + path + "'"); } // try to decode non-latin characters in url (MPS-20091) try { url = new URL(url.getProtocol(), url.getHost(), url.getPort(), URLDecoder.decode(url.getFile(), "UTF-8")); } catch (MalformedURLException e) { } catch (UnsupportedEncodingException e) { } return extractRoot(url, path); } /** * Attempts to extract classpath entry part from passed URL. */ @NotNull private static String extractRoot(@NotNull URL resourceURL, String resourcePath) { if (!((resourcePath.startsWith("/") || resourcePath.startsWith("\\")))) { throw new BuildException("cannot detect jar location: precondition failed for" + resourcePath); } String protocol = resourceURL.getProtocol(); String resultPath = null; if (MPSClasspathUtil.FILE.equals(protocol)) { String path = resourceURL.getFile(); String testPath = path.replace('\\', '/').toLowerCase(); String testResourcePath = resourcePath.replace('\\', '/').toLowerCase(); if (testPath.endsWith(testResourcePath)) { resultPath = path.substring(0, path.length() - resourcePath.length()); } } else if (MPSClasspathUtil.JAR.equals(protocol)) { String fullPath = resourceURL.getFile(); int delimiter = fullPath.indexOf(MPSClasspathUtil.JAR_DELIMITER); if (delimiter >= 0) { String archivePath = fullPath.substring(0, delimiter); if (archivePath.startsWith(MPSClasspathUtil.FILE + MPSClasspathUtil.PROTOCOL_DELIMITER)) { resultPath = archivePath.substring(MPSClasspathUtil.FILE.length() + MPSClasspathUtil.PROTOCOL_DELIMITER.length()); } } } if (resultPath == null) { throw new BuildException("cannot detect jar location: url=`" + resourceURL.toString() + "'"); } if (resultPath.endsWith(File.separator)) { resultPath = resultPath.substring(0, resultPath.length() - 1); } return replace(resultPath, "%20", " "); } @NotNull private static String replace(@NotNull String text, @NotNull String from, @NotNull String to) { final StringBuilder result = new StringBuilder(text.length()); final int len = from.length(); for (int i = 0; i < text.length(); i++) { if (text.regionMatches(i, from, 0, len)) { result.append(to); i += len - 1; continue; } result.append(text.charAt(i)); } return result.toString(); } public static List<File> getClassPathRootsFromDependencies(Project project) { List<File> roots = new ArrayList<File>(); String mpsHome = project.getProperty("artifacts.mps"); String pluginHome = project.getProperty("artifacts.mpsPlugin"); String ideaHome = project.getProperty("artifacts.IDEA"); String mpsCoreHome = project.getProperty("artifacts.mpsBootstrapCore"); String mpsWorkbenchHome = project.getProperty("artifacts.mpsWorkbench"); if ((mpsHome != null && mpsHome.length() > 0)) { // buildMPS roots.add(new File(project.resolveFile(mpsHome).getPath(), "lib")); } else if ((pluginHome != null && pluginHome.length() > 0) && (ideaHome != null && ideaHome.length() > 0)) { // buildPlugin + IDEA roots.add(new File(project.resolveFile(ideaHome).getPath(), "lib")); roots.add(new File(project.resolveFile(pluginHome).getPath(), "mps-core/lib")); } else if ((mpsCoreHome != null && mpsCoreHome.length() > 0) && (ideaHome != null && ideaHome.length() > 0)) { // buildCore + IDEA roots.add(new File(project.resolveFile(mpsCoreHome).getPath(), "lib")); roots.add(new File(project.resolveFile(ideaHome).getPath(), "lib")); if ((mpsWorkbenchHome != null && mpsWorkbenchHome.length() > 0)) { roots.add(new File(project.resolveFile(mpsWorkbenchHome).getPath(), "lib")); } } return roots; } public static void gatherAllClassesAndJarsUnder(File dir, Set<File> result) { if (dir.getName().equals("classes") || dir.getName().equals("classes_gen") || dir.getName().equals("apiclasses")) { result.add(dir); return; } File[] children = dir.listFiles(); // we do not want trove different from ours in $mps.home$/lib String troveJar = "trove" + File.separator + "lib" + File.separator + "trove"; // to provide right order of class loading, // files go first for (File f : children) { if (!(f.isDirectory())) { if (f.getName().endsWith(".jar") && !(f.getName().contains("ant.jar")) && !(f.getPath().contains(troveJar))) { result.add(f); } } } for (File f : children) { if (f.isDirectory()) { if (f.getName().equals("classes") || f.getName().equals("classes_gen")) { result.add(f); } else { gatherAllClassesAndJarsUnder(f, result); } } } } }