Bug 212662 [prov] eclipse.exe should be deleted when all IUs have been uninstalled
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/internal/p2/core/helpers/FileUtils.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/internal/p2/core/helpers/FileUtils.java
index ee8cad5..59759f6 100644
--- a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/internal/p2/core/helpers/FileUtils.java
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/internal/p2/core/helpers/FileUtils.java
@@ -12,6 +12,7 @@
 
 import java.io.*;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.zip.*;
 import org.eclipse.core.runtime.*;
 import org.eclipse.osgi.util.NLS;
@@ -21,10 +22,10 @@
 	/**
 	 * Unzip from a File to an output directory.
 	 */
-	public static void unzipFile(File zipFile, File outputDir) throws IOException {
+	public static File[] unzipFile(File zipFile, File outputDir) throws IOException {
 		InputStream in = new FileInputStream(zipFile);
 		try {
-			unzipStream(in, zipFile.length(), outputDir, null, null);
+			return unzipStream(in, zipFile.length(), outputDir, null, null);
 		} catch (IOException e) {
 			// add the file name to the message
 			throw new IOException(NLS.bind(Messages.Util_Error_Unzipping, zipFile, e.getMessage()));
@@ -37,10 +38,10 @@
 	 * Unzip from a File to an output directory, with progress indication.
 	 * monitor may be null.
 	 */
-	public static void unzipFile(File zipFile, File outputDir, String taskName, IProgressMonitor monitor) throws IOException {
+	public static File[] unzipFile(File zipFile, File outputDir, String taskName, IProgressMonitor monitor) throws IOException {
 		InputStream in = new FileInputStream(zipFile);
 		try {
-			unzipStream(in, zipFile.length(), outputDir, taskName, monitor);
+			return unzipStream(in, zipFile.length(), outputDir, taskName, monitor);
 		} catch (IOException e) {
 			// add the file name to the message
 			throw new IOException(NLS.bind(Messages.Util_Error_Unzipping, zipFile, e.getMessage()));
@@ -53,11 +54,11 @@
 	 * Unzip from a URL to an output directory, with progress indication.
 	 * monitor may be null.
 	 */
-	public static void unzipURL(URL zipURL, File outputDir, String taskName, IProgressMonitor monitor) throws IOException {
+	public static File[] unzipURL(URL zipURL, File outputDir, String taskName, IProgressMonitor monitor) throws IOException {
 		int size = zipURL.openConnection().getContentLength();
 		InputStream in = zipURL.openStream();
 		try {
-			unzipStream(in, size, outputDir, taskName, monitor);
+			return unzipStream(in, size, outputDir, taskName, monitor);
 		} catch (IOException e) {
 			// add the URL to the message
 			throw new IOException(NLS.bind(Messages.Util_Error_Unzipping, zipURL, e.getMessage()));
@@ -69,7 +70,7 @@
 	/**
 	 * Unzip from an InputStream to an output directory.
 	 */
-	public static void unzipStream(InputStream stream, long size, File outputDir, String taskName, IProgressMonitor monitor) throws IOException {
+	public static File[] unzipStream(InputStream stream, long size, File outputDir, String taskName, IProgressMonitor monitor) throws IOException {
 		InputStream is = monitor == null ? stream : stream; // new ProgressMonitorInputStream(stream, size, size, taskName, monitor); TODO Commented code
 		ZipInputStream in = new ZipInputStream(new BufferedInputStream(is));
 		ZipEntry ze = in.getNextEntry();
@@ -79,8 +80,10 @@
 			in.close();
 			throw new IOException(Messages.Util_Invalid_Zip_File_Format);
 		}
+		ArrayList unzippedFiles = new ArrayList();
 		do {
 			File outFile = new File(outputDir, ze.getName());
+			unzippedFiles.add(outFile);
 			if (ze.isDirectory()) {
 				outFile.mkdirs();
 			} else {
@@ -100,6 +103,8 @@
 			in.closeEntry();
 		} while ((ze = in.getNextEntry()) != null);
 		in.close();
+
+		return (File[]) unzippedFiles.toArray(new File[unzippedFiles.size()]);
 	}
 
 	// Delete empty directories under dir, including dir itself.
diff --git a/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/Generator.java b/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/Generator.java
index 03ad322..997063d 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/Generator.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/Generator.java
@@ -362,6 +362,8 @@
 			}
 		}
 		touchpointData.put("install", configurationData); //$NON-NLS-1$
+		String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$
+		touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$
 		cu.addTouchpointData(new TouchpointData(touchpointData));
 		resultantIUs.add(MetadataFactory.createInstallableUnit(cu));
 
diff --git a/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/MetadataGeneratorHelper.java b/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/MetadataGeneratorHelper.java
index b5cbcb8..69b66bd 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/MetadataGeneratorHelper.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.generator/src/org/eclipse/equinox/p2/metadata/generator/MetadataGeneratorHelper.java
@@ -346,6 +346,8 @@
 		//Create config info for the CU
 		String configurationData = "unzip(source:@artifact, target:${installFolder});";
 		touchpointData.put("install", configurationData);
+		String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$
+		touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$
 		cu.addTouchpointData(new TouchpointData(touchpointData));
 		resultantIUs.add(MetadataFactory.createInstallableUnit(cu));
 
@@ -393,6 +395,8 @@
 		if (!info.getOS().equals(org.eclipse.osgi.service.environment.Constants.OS_WIN32))
 			configurationData += " chmod(targetDir:${installFolder}, targetFile:" + launcher.getName() + ", permissions:755);";
 		touchpointData.put("install", configurationData);
+		String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$
+		touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$
 		cu.addTouchpointData(new TouchpointData(touchpointData));
 		resultantIUs.add(MetadataFactory.createInstallableUnitFragment(cu));
 
diff --git a/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/NativeTouchpoint.java b/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/NativeTouchpoint.java
index 6ec683a..b32176c 100644
--- a/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/NativeTouchpoint.java
+++ b/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/NativeTouchpoint.java
@@ -12,8 +12,7 @@
 
 import java.io.File;
 import java.net.URL;
-import java.util.Collection;
-import java.util.Map;
+import java.util.*;
 import org.eclipse.core.runtime.*;
 import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
 import org.eclipse.equinox.p2.artifact.repository.*;
@@ -51,40 +50,26 @@
 		if (actionId.equals("unzip")) {
 			return new ProvisioningAction() {
 				public IStatus execute(Map parameters) {
-					String source = (String) parameters.get("source");
-					if (source == null)
-						return createError("The \"source\" parameter was not set in the \"unzip\" action.");
-					String target = (String) parameters.get("target");
-					if (target == null)
-						return createError("The \"target\" parameter was not set in the \"unzip\" action.");
-
-					if (source.equals("@artifact")) {
-						IInstallableUnit iu = (IInstallableUnit) parameters.get("iu");
-						//TODO: fix wherever this occurs -- investigate as this is probably not desired
-						if (iu.getArtifacts() == null || iu.getArtifacts().length == 0)
-							return Status.OK_STATUS;
-
-						IArtifactKey artifactKey = iu.getArtifacts()[0];
-
-						IFileArtifactRepository downloadCache = getDownloadCacheRepo();
-						if (downloadCache == null)
-							return createError("The download cache could not be found for the \"unzip\" action.");
-						File fileLocation = downloadCache.getArtifactFile(artifactKey);
-						if ((fileLocation == null) || !fileLocation.exists())
-							return createError("The artifact for " + artifactKey + " is not available");
-						source = fileLocation.getAbsolutePath();
-					}
-
-					new Zip().unzip(source, target, null);
-					return Status.OK_STATUS;
+					return unzip(parameters);
 				}
 
 				public IStatus undo(Map parameters) {
-					//TODO: implement undo
-					return Status.OK_STATUS;
+					return cleanupzip(parameters);
 				}
 			};
 		}
+		if (actionId.equals("cleanupzip")) {
+			return new ProvisioningAction() {
+				public IStatus execute(Map parameters) {
+					return cleanupzip(parameters);
+				}
+
+				public IStatus undo(Map parameters) {
+					return unzip(parameters);
+				}
+			};
+		}
+
 		if (actionId.equals("chmod")) {
 			return new ProvisioningAction() {
 				public IStatus execute(Map parameters) {
@@ -191,4 +176,81 @@
 		touchpointParameters.put("installFolder", getInstallFolder(profile));
 		return null;
 	}
+
+	IStatus unzip(Map parameters) {
+		String source = (String) parameters.get("source");
+		if (source == null)
+			return createError("The \"source\" parameter was not set in the \"unzip\" action.");
+
+		String originalSource = source;
+		String target = (String) parameters.get("target");
+		if (target == null)
+			return createError("The \"target\" parameter was not set in the \"unzip\" action.");
+
+		IInstallableUnit iu = (IInstallableUnit) parameters.get("iu");
+		Profile profile = (Profile) parameters.get("profile");
+
+		if (source.equals("@artifact")) {
+			//TODO: fix wherever this occurs -- investigate as this is probably not desired
+			if (iu.getArtifacts() == null || iu.getArtifacts().length == 0)
+				return Status.OK_STATUS;
+
+			IArtifactKey artifactKey = iu.getArtifacts()[0];
+
+			IFileArtifactRepository downloadCache = getDownloadCacheRepo();
+			if (downloadCache == null)
+				return createError("The download cache could not be found for the \"unzip\" action.");
+			File fileLocation = downloadCache.getArtifactFile(artifactKey);
+			if ((fileLocation == null) || !fileLocation.exists())
+				return createError("The artifact for " + artifactKey + " is not available");
+			source = fileLocation.getAbsolutePath();
+		}
+
+		File[] unzippedFiles = new Zip().unzip(source, target, null);
+		StringBuffer unzippedFileNameBuffer = new StringBuffer();
+		for (int i = 0; i < unzippedFiles.length; i++)
+			unzippedFileNameBuffer.append(unzippedFiles[i].getAbsolutePath()).append("|");
+
+		String unzipped = profile.setInstallableUnitProfileProperty(iu, "unzipped" + "|" + originalSource + "|" + target, unzippedFileNameBuffer.toString());
+
+		return Status.OK_STATUS;
+	}
+
+	protected IStatus cleanupzip(Map parameters) {
+		String source = (String) parameters.get("source");
+		if (source == null)
+			return createError("The \"source\" parameter was not set in the \"cleanupzip\" action.");
+		String target = (String) parameters.get("target");
+		if (target == null)
+			return createError("The \"target\" parameter was not set in the \"cleanupzip\" action.");
+
+		IInstallableUnit iu = (IInstallableUnit) parameters.get("iu");
+		Profile profile = (Profile) parameters.get("profile");
+
+		String unzipped = profile.getInstallableUnitProfileProperty(iu, "unzipped" + "|" + source + "|" + target);
+
+		if (unzipped == null)
+			return Status.OK_STATUS;
+
+		StringTokenizer tokenizer = new StringTokenizer(unzipped, "|");
+		List directories = new ArrayList();
+		while (tokenizer.hasMoreTokens()) {
+			String fileName = tokenizer.nextToken();
+			File file = new File(fileName);
+			if (!file.exists())
+				continue;
+
+			if (file.isDirectory())
+				directories.add(file);
+			else
+				file.delete();
+		}
+
+		for (Iterator it = directories.iterator(); it.hasNext();) {
+			File directory = (File) it.next();
+			directory.delete();
+		}
+
+		return Status.OK_STATUS;
+	}
 }
diff --git a/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/Zip.java b/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/Zip.java
index 6be09cd..3add7ce 100644
--- a/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/Zip.java
+++ b/bundles/org.eclipse.equinox.p2.touchpoint.natives/src/org/eclipse/equinox/internal/p2/touchpoint/natives/Zip.java
@@ -18,7 +18,7 @@
 
 //TODO Be careful here with the permissions.... We may need to have a proper unzip technology here that supports file permissions for linux
 public class Zip {
-	public void unzip(String source, String destination, String backupDir) {
+	public File[] unzip(String source, String destination, String backupDir) {
 		//		IArtifact artifact = data.getArtifact();
 		//		String destination = performVariableSubstitutions(data.getDestination());
 		//		if (canInstallArtifact()) {
@@ -61,7 +61,7 @@
 			}
 			try {
 				String taskName = NLS.bind(Messages.unzipping, source);
-				FileUtils.unzipFile(zipFile, new File(destination), taskName, new NullProgressMonitor());
+				return FileUtils.unzipFile(zipFile, new File(destination), taskName, new NullProgressMonitor());
 			} catch (IOException e) {
 				System.out.println(this.getClass().getName() + " something went wrong when unzipping");
 				System.out.println("zipfile: " + zipFile.getAbsolutePath());
@@ -75,5 +75,6 @@
 			//			monitor.done();
 		}
 		//		}
+		return null;
 	}
 }