Bug 501617 - BuildPathSupport should support unexploded bundles
Support extracting requested library jars from a bundle to an internal
location.
Change-Id: I1c5aa0989d15aed4de219b2b20389165fa1529ea
Signed-off-by: Brian de Alwis <bsd@mt.ca>
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.java
index f8f219b..36a51e1 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.java
@@ -14,7 +14,12 @@
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URL;
+import java.nio.file.Files;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;
@@ -25,8 +30,10 @@
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
@@ -106,12 +113,97 @@
return null;
}
+ private IPath getBundleFileLocation(String aBundleId, VersionRange aVersionRange, String filePath) {
+ BundleInfo bundleInfo = P2Utils.findBundle(aBundleId, aVersionRange, false);
+
+ if (bundleInfo != null) {
+ resolvedVersion = bundleInfo.getVersion();
+ IPath bundleLocation = P2Utils.getBundleLocationPath(bundleInfo);
+ if(bundleLocation != null) {
+ File bundleLoc = bundleLocation.toFile();
+ if(bundleLoc.isDirectory() && new File(bundleLoc, filePath).exists()) {
+ return bundleLocation.append(filePath);
+ } else if (bundleLoc.isFile() && bundleLoc.getName().endsWith(".jar")) { //$NON-NLS-1$
+ return extractArchiveEntry(bundleInfo, bundleLoc, filePath);
+ }
+ }
+ } else {
+ // p2's simple configurator is not available. Let's try with installed bundles from the running platform.
+ // Note: Source bundles are typically not available at run time!
+ Bundle[] bundles= Platform.getBundles(aBundleId, aVersionRange.toString());
+ Bundle bestMatch= null;
+ if (bundles != null) {
+ for (int i= 0; i < bundles.length; i++) {
+ Bundle bundle= bundles[i];
+ if (bestMatch == null || bundle.getState() > bestMatch.getState()) {
+ bestMatch= bundle;
+ }
+ }
+ }
+ if (bestMatch != null) {
+ try {
+ resolvedVersion= bestMatch.getVersion().toString();
+ URL rootUrl= bestMatch.getEntry(filePath);
+ if (rootUrl != null) {
+ URL fileRootUrl= FileLocator.toFileURL(rootUrl);
+ return new Path(fileRootUrl.getPath());
+ }
+ } catch (IOException ex) {
+ JUnitCorePlugin.log(ex);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Extract the a library from a bundle to a known location.
+ *
+ * @param bundleInfo bundle information, used to create a reproducible location to hold the
+ * extracted library
+ * @param bundleLoc the bundle jar
+ * @param filePath the file path within the bundle of the library to be extracted
+ * @return the path to the extracted library
+ */
+ private IPath extractArchiveEntry(BundleInfo bundleInfo, File bundleLoc, String filePath) {
+ IPath container= JUnitCorePlugin.getDefault().getStateLocation().append(bundleInfo.getSymbolicName()).append(bundleInfo.getVersion());
+ IPath extractedPath= container.append(filePath);
+ if (extractedPath.toFile().exists()) {
+ // previously extracted
+ return extractedPath;
+ }
+ try (JarFile jar= new JarFile(bundleLoc)) {
+ ZipEntry entry= jar.getEntry(filePath);
+ if (entry != null) {
+ if (!container.toFile().exists() && !container.toFile().mkdirs()) {
+ JUnitCorePlugin.log(new Status(IStatus.ERROR, JUnitCorePlugin.CORE_PLUGIN_ID, "Unable to create directory to hold " + filePath)); //$NON-NLS-1$
+ return null;
+ }
+ try (InputStream input= jar.getInputStream(entry);
+ OutputStream output= Files.newOutputStream(extractedPath.toFile().toPath())) {
+ int bytesRead;
+ byte[] buffer= new byte[8192];
+ while ((bytesRead= input.read(buffer)) > 0) {
+ output.write(buffer, 0, bytesRead);
+ }
+ }
+ return extractedPath;
+ }
+ } catch (IOException ex) {
+ JUnitCorePlugin.log(ex);
+ }
+ return null;
+ }
+
public IClasspathEntry getLibraryEntry() {
IPath bundleLocation = getBundleLocation(bundleId, versionRange);
if (bundleLocation != null) {
IPath bundleRootLocation= null;
if (bundleRoot != null) {
- bundleRootLocation= getLocationIfExists(bundleLocation, bundleRoot);
+ bundleRootLocation= getBundleFileLocation(bundleId, versionRange, bundleRoot);
+ if(bundleRootLocation == null) {
+ bundleRootLocation= getLocationIfExists(bundleLocation, bundleRoot);
+ }
}
if (bundleRootLocation == null && binaryImportedRoot != null) {
bundleRootLocation= getLocationIfExists(bundleLocation, binaryImportedRoot);