Roland Grunberg c3ea0c
From aabcf5acff194b807c4d0bcf68425c3452c90339 Mon Sep 17 00:00:00 2001
Roland Grunberg 03cbc7
From: Roland Grunberg <rgrunber@redhat.com>
Roland Grunberg 03cbc7
Date: Fri, 12 Sep 2014 10:27:14 -0400
Roland Grunberg 03cbc7
Subject: [PATCH] Add support for regenerating bundle versions for symlinks.
Roland Grunberg 03cbc7
Roland Grunberg 03cbc7
When the version field in a bundle info file corresponds to a bundle
Roland Grunberg 03cbc7
whose location is a symbolic link, the correct version should be
Roland Grunberg 03cbc7
regenerated every time, in case a change has occured.
Roland Grunberg 03cbc7
Roland Grunberg 03cbc7
Change-Id: Ifbe8efed2218a8a1250fd1ac59f0cdd6bdd5f309
Roland Grunberg 03cbc7
---
Roland Grunberg 03cbc7
 .../META-INF/MANIFEST.MF                           |   1 +
Roland Grunberg bff49e
 .../utils/SimpleConfiguratorUtils.java             | 106 ++++++++++++++++++++-
Roland Grunberg bff49e
 2 files changed, 106 insertions(+), 1 deletion(-)
Roland Grunberg 03cbc7
Roland Grunberg 03cbc7
diff --git rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/META-INF/MANIFEST.MF rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/META-INF/MANIFEST.MF
Roland Grunberg bff49e
index d88d0a6..07fe087 100644
Roland Grunberg 03cbc7
--- rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/META-INF/MANIFEST.MF
Roland Grunberg 03cbc7
+++ rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/META-INF/MANIFEST.MF
Roland Grunberg 03cbc7
@@ -9,6 +9,7 @@ Bundle-Activator: org.eclipse.equinox.internal.simpleconfigurator.Activator
Roland Grunberg 03cbc7
 Bundle-ActivationPolicy: lazy
Roland Grunberg 03cbc7
 Import-Package: org.eclipse.osgi.framework.console;version="1.0.0";resolution:=optional,
Roland Grunberg 03cbc7
  org.eclipse.osgi.service.datalocation;version="1.0.0";resolution:=optional,
Roland Grunberg 03cbc7
+ org.eclipse.osgi.util;version="1.1.0",
Roland Grunberg 03cbc7
  org.osgi.framework;version="1.3.0",
Roland Grunberg 03cbc7
  org.osgi.framework.namespace;version="1.0.0",
Roland Grunberg 03cbc7
  org.osgi.framework.wiring;version="1.2.0",
Roland Grunberg 03cbc7
diff --git rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorUtils.java rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorUtils.java
Roland Grunberg c3ea0c
index ab69b88..d6bf121 100644
Roland Grunberg 03cbc7
--- rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorUtils.java
Roland Grunberg 03cbc7
+++ rt.equinox.p2/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/utils/SimpleConfiguratorUtils.java
c24287
@@ -20,8 +20,12 @@
c73623
 import java.nio.file.Files;
c24287
 import java.nio.file.attribute.FileTime;
Roland Grunberg 03cbc7
 import java.util.*;
Roland Grunberg 03cbc7
+import java.util.jar.JarFile;
Roland Grunberg 03cbc7
+import java.util.zip.ZipEntry;
Roland Grunberg 03cbc7
+import java.util.zip.ZipFile;
Roland Grunberg 03cbc7
 import org.eclipse.equinox.internal.simpleconfigurator.Activator;
Roland Grunberg 03cbc7
-import org.osgi.framework.Version;
Roland Grunberg 03cbc7
+import org.eclipse.osgi.util.ManifestElement;
Roland Grunberg 03cbc7
+import org.osgi.framework.*;
Roland Grunberg 03cbc7
 
Roland Grunberg 03cbc7
 public class SimpleConfiguratorUtils {
Roland Grunberg 03cbc7
 
c24287
@@ -282,6 +286,16 @@
Roland Grunberg 03cbc7
 		String symbolicName = tok.nextToken().trim();
Roland Grunberg 03cbc7
 		String version = tok.nextToken().trim();
Roland Grunberg 03cbc7
 		URI location = parseLocation(tok.nextToken().trim());
Roland Grunberg bff49e
+		if (base != null) {
Roland Grunberg bff49e
+			URI absLoc = URIUtil.append(base, location.toString());
c73623
+			java.nio.file.Path absPath = java.nio.file.Paths.get(absLoc);
Roland Grunberg bff49e
+			// Symbolic links may change outside Eclipse so regenerate proper bundle version.
Roland Grunberg c3ea0c
+			if (Files.isSymbolicLink(absPath) && absPath.toFile().isFile()) {
Roland Grunberg bff49e
+				// We can't depend on org.eclipse.equinox.internal.frameworkadmin.utils.Utils
Roland Grunberg bff49e
+				Dictionary<string, string=""> manifest = getOSGiManifest(absLoc);
Roland Grunberg bff49e
+				version = manifest.get(Constants.BUNDLE_VERSION);
Roland Grunberg bff49e
+			}
Roland Grunberg 03cbc7
+		}
Roland Grunberg 03cbc7
 		int startLevel = Integer.parseInt(tok.nextToken().trim());
c35a6c
 		boolean markedAsStarted = Boolean.parseBoolean(tok.nextToken());
Roland Grunberg 03cbc7
 		BundleInfo result = new BundleInfo(symbolicName, version, location, startLevel, markedAsStarted);
c24287
@@ -420,4 +434,93 @@
Roland Grunberg 03cbc7
 		}
c24287
 		return lastModified;
Roland Grunberg 03cbc7
 	}
Roland Grunberg 03cbc7
+
Roland Grunberg 03cbc7
+	private static Dictionary<string, string=""> getOSGiManifest(URI location) {
Roland Grunberg 03cbc7
+		if (location == null)
Roland Grunberg 03cbc7
+			return null;
Roland Grunberg 03cbc7
+		// if we have a file-based URL that doesn't end in ".jar" then...
Roland Grunberg 03cbc7
+		if (FILE_SCHEME.equals(location.getScheme()))
Roland Grunberg 03cbc7
+			return basicLoadManifest(URIUtil.toFile(location));
Roland Grunberg 03cbc7
+
Roland Grunberg 03cbc7
+		try {
Roland Grunberg 03cbc7
+			URL url = new URL("jar:" + location.toString() + "!/"); //$NON-NLS-1$//$NON-NLS-2$
Roland Grunberg 03cbc7
+			JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
Roland Grunberg 03cbc7
+			ZipFile jar = jarConnection.getJarFile();
Roland Grunberg 03cbc7
+
Roland Grunberg 03cbc7
+			try {
Roland Grunberg 03cbc7
+				ZipEntry entry = jar.getEntry(JarFile.MANIFEST_NAME);
Roland Grunberg 03cbc7
+				if (entry == null)
Roland Grunberg 03cbc7
+					return null;
Roland Grunberg 03cbc7
+
Roland Grunberg 03cbc7
+				Map<string, string=""> manifest = ManifestElement.parseBundleManifest(jar.getInputStream(entry), null);
Roland Grunberg 03cbc7
+				return manifestToProperties(manifest);
Roland Grunberg 03cbc7
+			} catch (BundleException e) {
Roland Grunberg 03cbc7
+				return null;
Roland Grunberg 03cbc7
+			} finally {
Roland Grunberg 03cbc7
+				jar.close();
Roland Grunberg 03cbc7
+			}
Roland Grunberg 03cbc7
+		} catch (IOException e) {
Roland Grunberg 03cbc7
+			if (System.getProperty("osgi.debug") != null) { //$NON-NLS-1$
Roland Grunberg 03cbc7
+				System.err.println("location=" + location); //$NON-NLS-1$
Roland Grunberg 03cbc7
+				e.printStackTrace();
Roland Grunberg 03cbc7
+			}
Roland Grunberg 03cbc7
+		}
Roland Grunberg 03cbc7
+		return null;
Roland Grunberg 03cbc7
+	}
Roland Grunberg 03cbc7
+
Roland Grunberg 03cbc7
+	private static Dictionary<string, string=""> basicLoadManifest(File bundleLocation) {
Roland Grunberg 03cbc7
+		InputStream manifestStream = null;
Roland Grunberg 03cbc7
+		ZipFile jarFile = null;
Roland Grunberg 03cbc7
+		try {
Roland Grunberg 03cbc7
+			try {
Roland Grunberg 03cbc7
+				// Handle a JAR'd bundle
Roland Grunberg 03cbc7
+				if (bundleLocation.isFile()) {
Roland Grunberg 03cbc7
+					jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
Roland Grunberg 03cbc7
+					ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME);
Roland Grunberg 03cbc7
+					if (manifestEntry != null) {
Roland Grunberg 03cbc7
+						manifestStream = jarFile.getInputStream(manifestEntry);
Roland Grunberg 03cbc7
+					}
Roland Grunberg 03cbc7
+				} else {
Roland Grunberg 03cbc7
+					// we have a directory-based bundle
Roland Grunberg 03cbc7
+					File bundleManifestFile = new File(bundleLocation, JarFile.MANIFEST_NAME);
Roland Grunberg 03cbc7
+					if (bundleManifestFile.exists())
Roland Grunberg 03cbc7
+						manifestStream = new BufferedInputStream(new FileInputStream(new File(bundleLocation, JarFile.MANIFEST_NAME)));
Roland Grunberg 03cbc7
+				}
Roland Grunberg 03cbc7
+			} catch (IOException e) {
Roland Grunberg 03cbc7
+				//ignore
Roland Grunberg 03cbc7
+			}
Roland Grunberg 03cbc7
+
Roland Grunberg 03cbc7
+			try {
Roland Grunberg 03cbc7
+				Map<string, string=""> manifest = ManifestElement.parseBundleManifest(manifestStream, null);
Roland Grunberg 03cbc7
+				return manifestToProperties(manifest);
Roland Grunberg 03cbc7
+			} catch (IOException ioe) {
Roland Grunberg 03cbc7
+				return null;
Roland Grunberg 03cbc7
+			} catch (BundleException e) {
Roland Grunberg 03cbc7
+				return null;
Roland Grunberg 03cbc7
+			}
Roland Grunberg 03cbc7
+		} finally {
Roland Grunberg 03cbc7
+			try {
Roland Grunberg 03cbc7
+				if (manifestStream != null)
Roland Grunberg 03cbc7
+					manifestStream.close();
Roland Grunberg 03cbc7
+			} catch (IOException e1) {
Roland Grunberg 03cbc7
+				//Ignore
Roland Grunberg 03cbc7
+			}
Roland Grunberg 03cbc7
+			try {
Roland Grunberg 03cbc7
+				if (jarFile != null)
Roland Grunberg 03cbc7
+					jarFile.close();
Roland Grunberg 03cbc7
+			} catch (IOException e2) {
Roland Grunberg 03cbc7
+				//Ignore
Roland Grunberg 03cbc7
+			}
Roland Grunberg 03cbc7
+		}
Roland Grunberg 03cbc7
+	}
Roland Grunberg 03cbc7
+
Roland Grunberg 03cbc7
+	private static Dictionary<string, string=""> manifestToProperties(Map<string, string=""> d) {
Roland Grunberg 03cbc7
+		Iterator<string> iter = d.keySet().iterator();
Roland Grunberg 03cbc7
+		Dictionary<string, string=""> result = new Hashtable<string, string="">();
Roland Grunberg 03cbc7
+		while (iter.hasNext()) {
Roland Grunberg 03cbc7
+			String key = iter.next();
Roland Grunberg 03cbc7
+			result.put(key, d.get(key));
Roland Grunberg 03cbc7
+		}
Roland Grunberg 03cbc7
+		return result;
Roland Grunberg 03cbc7
+	}
Roland Grunberg 03cbc7
 }