| /******************************************************************************* |
| * Copyright (c) 2008, 2011 Sonatype Inc. and others. |
| * 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 |
| * |
| * Contributors: |
| * Sonatype Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.tycho.core.osgitools.targetplatform; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.FileInputStream; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| import org.codehaus.plexus.component.annotations.Component; |
| import org.codehaus.plexus.logging.AbstractLogEnabled; |
| import org.codehaus.plexus.util.xml.XmlStreamReader; |
| import org.codehaus.plexus.util.xml.Xpp3Dom; |
| import org.codehaus.plexus.util.xml.Xpp3DomBuilder; |
| |
| /** |
| * Finds bundles in Eclipse installation. |
| * |
| * See http://wiki.eclipse.org/Equinox_p2_Getting_Started See |
| * http://mea-bloga.blogspot.com/2008/04/new-target-platform-preference.html |
| * |
| * @author igor |
| * |
| */ |
| |
| @Component(role = EclipseInstallationLayout.class, instantiationStrategy = "per-lookup") |
| public class EclipseInstallationLayout extends AbstractLogEnabled { |
| |
| private static final class FEATURE_FILTER implements FileFilter { |
| @Override |
| public boolean accept(File pathname) { |
| if (pathname.getName().startsWith(".")) { |
| // filter out all dot files (like .svn or .DS_Store). |
| return false; |
| } |
| return pathname.isDirectory() || pathname.getName().endsWith(".jar"); |
| } |
| } |
| |
| public static final String PLUGINS = "plugins"; |
| public static final String FEATURES = "features"; |
| |
| private File location; |
| private File dropinsLocation; |
| |
| public void setLocation(File location) { |
| this.location = location; |
| this.dropinsLocation = new File(location, "dropins"); |
| } |
| |
| public File getLocation() { |
| return location; |
| } |
| |
| public Set<File> getFeatures(File site) { |
| Set<File> result = new LinkedHashSet<>(); |
| File[] features = new File(site, FEATURES).listFiles(new FEATURE_FILTER()); |
| if (features != null) { |
| result.addAll(Arrays.asList(features)); |
| } |
| |
| return result; |
| } |
| |
| public Set<File> getInstalledPlugins() { |
| Set<File> result = new LinkedHashSet<>(); |
| try { |
| result.addAll(readBundlesTxt(location)); |
| } catch (IOException e) { |
| getLogger().warn("Exception reading P2 bundles list", e); |
| } |
| return result; |
| } |
| |
| public Set<File> getPlugins(File site) { |
| Set<File> result = new LinkedHashSet<>(); |
| |
| addPlugins(result, new File(site, PLUGINS).listFiles()); |
| |
| // check for bundles in the root of dropins directory |
| if (dropinsLocation.equals(site)) { |
| addPlugins(result, site.listFiles()); |
| } |
| |
| return result; |
| } |
| |
| private void addPlugins(Set<File> result, File[] plugins) { |
| if (plugins != null) { |
| for (File plugin : plugins) { |
| if (plugin.isDirectory() && isDirectoryPlugin(plugin)) { |
| result.add(plugin); |
| } else if (plugin.isFile() && plugin.getName().endsWith(".jar")) { |
| result.add(plugin); |
| } |
| } |
| } |
| } |
| |
| private boolean isDirectoryPlugin(File plugin) { |
| return new File(plugin, "META-INF/MANIFEST.MF").canRead(); |
| } |
| |
| public Set<File> getSites() { |
| Set<File> result = new LinkedHashSet<>(); |
| |
| if (location == null) { |
| return result; |
| } |
| |
| if (new File(location, PLUGINS).isDirectory()) { |
| result.add(location); |
| } |
| |
| File platform = new File(location, "configuration/org.eclipse.update/platform.xml"); |
| if (platform.canRead()) { |
| try { |
| try (FileInputStream is = new FileInputStream(platform)) { |
| XmlStreamReader reader = new XmlStreamReader(is); |
| Xpp3Dom dom = Xpp3DomBuilder.build(reader); |
| Xpp3Dom[] sites = dom.getChildren("site"); |
| for (Xpp3Dom site : sites) { |
| String enabled = site.getAttribute("enabled"); |
| if (enabled == null || Boolean.parseBoolean(enabled)) { |
| File dir = parsePlatformURL(location, site.getAttribute("url")); |
| if (dir != null) { |
| result.add(dir); |
| } |
| } |
| } |
| } |
| } catch (Exception e) { |
| getLogger().warn("Exception parsing " + toString(platform), e); |
| } |
| } |
| |
| addLinks(result, location, new File(location, "links")); |
| |
| // deal with dropins folder |
| result.add(dropinsLocation); |
| |
| File[] dropinsFiles = dropinsLocation.listFiles(); |
| if (dropinsFiles != null) { |
| for (File dropinsFile : dropinsFiles) { |
| File plugins = new File(dropinsFile, PLUGINS); |
| if (plugins.isDirectory()) { |
| result.add(plugins.getParentFile()); |
| continue; |
| } |
| plugins = new File(dropinsFile, "eclipse/plugins"); |
| if (plugins.isDirectory()) { |
| result.add(plugins.getParentFile()); |
| } |
| } |
| } |
| |
| addLinks(result, location, dropinsLocation); |
| |
| return result; |
| } |
| |
| private String toString(File file) { |
| return file.getAbsolutePath(); |
| } |
| |
| private void addLinks(Set<File> result, File targetPlatform, File linksFolder) { |
| File[] links = linksFolder.listFiles(); |
| if (links != null) { |
| for (File link : links) { |
| if (link.isFile() && link.canRead() && link.getName().endsWith(".link")) { |
| Properties props = new Properties(); |
| try { |
| try (InputStream is = new FileInputStream(link)) { |
| props.load(is); |
| } |
| String path = props.getProperty("path"); |
| if (path != null) { |
| File dir = new File(path); |
| if (!dir.isAbsolute() && targetPlatform.getParentFile() != null) { |
| dir = new File(targetPlatform.getParentFile(), path); |
| } |
| dir = dir.getAbsoluteFile(); |
| if (dir.isDirectory()) { |
| result.add(dir); |
| } |
| } |
| } catch (Exception e) { |
| getLogger().warn("Exception parsing " + toString(link), e); |
| continue; |
| } |
| } |
| } |
| } |
| } |
| |
| private static final String PLATFORM_BASE_PREFIX = "platform:/base/"; |
| private static final String FILE_PREFIX = "file:"; |
| |
| private File parsePlatformURL(File platformBase, String url) { |
| if (url == null) { |
| return null; |
| } |
| |
| url = url.replace('\\', '/'); |
| |
| String relPath = null; |
| if (url.startsWith(PLATFORM_BASE_PREFIX)) { |
| relPath = url.substring(PLATFORM_BASE_PREFIX.length()); |
| } else if (url.startsWith(FILE_PREFIX)) { |
| relPath = url.substring(FILE_PREFIX.length()); |
| } |
| |
| if (relPath == null) { |
| return null; |
| } |
| |
| if (relPath.length() > 0 && relPath.charAt(0) == '/') { |
| return new File(relPath); |
| } |
| |
| return new File(platformBase, relPath); |
| } |
| |
| private List<File> readBundlesTxt(File platformBase) throws IOException { |
| getLogger().debug("Reading P2 bundles list"); |
| |
| // there is no way to find location of bundle pool without access to P2 profile |
| // so lets assume equinox.launcher comes from the pool |
| File eclipseIni = new File(platformBase, "eclipse.ini"); |
| File pool = platformBase; |
| if (eclipseIni.isFile() && eclipseIni.canRead()) { |
| try (BufferedReader in = new BufferedReader(new FileReader(eclipseIni))) { |
| String str = null; |
| while ((str = in.readLine()) != null) { |
| if ("-startup".equals(str.trim())) { |
| str = in.readLine(); |
| if (str != null) { |
| File file = new File(str); |
| if (!file.isAbsolute()) { |
| file = new File(platformBase, str).getAbsoluteFile(); |
| } |
| pool = file.getParentFile().getParentFile().getAbsoluteFile(); |
| } |
| break; |
| } |
| } |
| } |
| } |
| |
| getLogger().debug("Bundle pool location " + toString(pool)); |
| |
| File bundlesInfo = new File(platformBase, "configuration/org.eclipse.equinox.simpleconfigurator/bundles.info"); |
| if (!bundlesInfo.isFile() || !bundlesInfo.canRead()) { |
| getLogger().info("Could not read P2 bundles list " + toString(bundlesInfo)); |
| return null; |
| } |
| |
| ArrayList<File> plugins = new ArrayList<>(); |
| |
| BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(bundlesInfo))); |
| String line; |
| try { |
| while ((line = r.readLine()) != null) { |
| if (line.startsWith("#")) //$NON-NLS-1$ |
| continue; |
| line = line.trim(); |
| if (line.length() == 0) |
| continue; |
| |
| // (expectedState is an integer). |
| if (line.startsWith("org.eclipse.equinox.simpleconfigurator.baseUrl" + "=")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| continue; |
| } |
| |
| StringTokenizer tok = new StringTokenizer(line, ","); |
| /* String symbolicName = */tok.nextToken(); |
| /* String version = */tok.nextToken(); |
| String location = tok.nextToken(); |
| |
| plugins.add(parsePlatformURL(pool, location)); |
| } |
| } finally { |
| r.close(); |
| } |
| |
| return plugins; |
| } |
| |
| } |