Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/.classpath7
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/.project28
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.pde.core.prefs4
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/META-INF/MANIFEST.MF9
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/about.html28
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/build.properties4
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/CommandStep.java74
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Main.java119
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackStep.java200
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackUnpackStep.java86
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/SignCommandStep.java98
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/StreamProcessor.java50
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/UnpackStep.java117
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Utils.java327
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/ZipProcessor.java245
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/pack-readme.html82
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/IProcessStep.java65
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessor.java394
-rw-r--r--bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessorExecutor.java141
20 files changed, 2085 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/.classpath b/bundles/org.eclipse.equinox.p2.jarprocessor/.classpath
new file mode 100644
index 000000000..7cdeb7319
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/CDC-1.1%Foundation-1.1"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/.project b/bundles/org.eclipse.equinox.p2.jarprocessor/.project
new file mode 100644
index 000000000..b3a3e9e0c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.equinox.p2.jarprocessor</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..186d5a85d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Tue Aug 28 11:20:14 EDT 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 000000000..69a27179c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,4 @@
+#Tue Aug 28 11:19:59 EDT 2007
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.jarprocessor/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..1d8bca319
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Jarprocessor Bundle
+Bundle-SymbolicName: org.eclipse.equinox.p2.jarprocessor
+Bundle-Version: 0.1.0.qualifier
+Bundle-RequiredExecutionEnvironment: CDC-1.1/Foundation-1.1,
+ J2SE-1.4
+Export-Package: org.eclipse.equinox.internal.p2.jarprocessor;x-internal:=true,
+ org.eclipse.equinox.p2.jarprocessor
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/about.html b/bundles/org.eclipse.equinox.p2.jarprocessor/about.html
new file mode 100644
index 000000000..460233046
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 2, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/build.properties b/bundles/org.eclipse.equinox.p2.jarprocessor/build.properties
new file mode 100644
index 000000000..34d2e4d2d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/CommandStep.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/CommandStep.java
new file mode 100644
index 000000000..2570a4f51
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/CommandStep.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+import org.eclipse.equinox.p2.jarprocessor.IProcessStep;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public abstract class CommandStep implements IProcessStep {
+ protected String command = null;
+ protected String extension = null;
+ private Properties options = null;
+ protected boolean verbose = false;
+
+ public CommandStep(Properties options, String command, String extension, boolean verbose) {
+ this.command = command;
+ this.extension = extension;
+ this.options = options;
+ this.verbose = verbose;
+ }
+
+ protected static int execute(String[] cmd) {
+ return execute(cmd, false);
+ }
+
+ protected static int execute(String[] cmd, boolean verbose) {
+ Runtime runtime = Runtime.getRuntime();
+ Process proc = null;
+ try {
+ proc = runtime.exec(cmd);
+ StreamProcessor errorStreamProcessor = new StreamProcessor(proc.getErrorStream(), StreamProcessor.STDERR, verbose); //$NON-NLS-1$
+ StreamProcessor outputStreamProcessor = new StreamProcessor(proc.getInputStream(), StreamProcessor.STDOUT, verbose); //$NON-NLS-1$
+ errorStreamProcessor.start();
+ outputStreamProcessor.start();
+ } catch (Exception e) {
+ if(verbose) {
+ System.out.println("Error executing command " + Utils.concat(cmd)); //$NON-NLS-1$
+ e.printStackTrace();
+ }
+ return -1;
+ }
+ try {
+ int result = proc.waitFor();
+ return result;
+ } catch (InterruptedException e) {
+ if(verbose)
+ e.printStackTrace();
+ }
+ return -1;
+ }
+
+ public Properties getOptions() {
+ if(options == null)
+ options = new Properties();
+ return options;
+ }
+
+ public void adjustInf(File input, Properties inf, List containers) {
+ //nothing
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Main.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Main.java
new file mode 100644
index 000000000..d06022a1f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Main.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.File;
+import org.eclipse.equinox.p2.jarprocessor.JarProcessor;
+import org.eclipse.equinox.p2.jarprocessor.JarProcessorExecutor;
+
+public class Main {
+
+ public static class Options {
+ public String outputDir = "."; //$NON-NLS-1$
+ public String signCommand = null;
+ public boolean pack = false;
+ public boolean repack = false;
+ public boolean unpack = false;
+ public boolean verbose = false;
+ public boolean processAll = false;
+ public File input = null;
+ }
+
+ private static void printUsage() {
+ System.out.println("[-option ...]... input"); //$NON-NLS-1$
+ System.out.println("The following options are supported:"); //$NON-NLS-1$
+ System.out.println("-processAll process all jars, regardless of whether they were previously normalized"); //$NON-NLS-1$
+ System.out.println(" By default only normalized jars will be processed."); //$NON-NLS-1$
+ System.out.println("-repack normalize jars "); //$NON-NLS-1$
+ System.out.println("-sign <command> sign jars using <command>"); //$NON-NLS-1$
+ System.out.println("-pack pack the jars. pack and repack are redundant unless"); //$NON-NLS-1$
+ System.out.println(" sign is also specified."); //$NON-NLS-1$
+ System.out.println("-unpack unpack pack.gz files. Unpack is mutually exclusive"); //$NON-NLS-1$
+ System.out.println(" with repack, sign and pack."); //$NON-NLS-1$
+ System.out.println();
+ System.out.println("-outputDir <dir> the output directory"); //$NON-NLS-1$
+ System.out.println("-verbose verbose mode "); //$NON-NLS-1$
+ }
+
+ public static Options processArguments(String[] args) {
+ if (args.length == 0) {
+ printUsage();
+ return null;
+ }
+
+ Options options = new Options();
+ int i = 0;
+ for (; i < args.length - 1; i++) {
+ if (args[i].equals("-pack")) {//$NON-NLS-1$
+ options.pack = true;
+ } else if (args[i].equals("-unpack")) { //$NON-NLS-1$
+ options.unpack = true;
+ } else if (args[i].equals("-sign") && i < args.length - 2) { //$NON-NLS-1$
+ if (args[i + 1].startsWith("-")) { //$NON-NLS-1$
+ printUsage();
+ return null;
+ }
+ options.signCommand = args[++i];
+ } else if (args[i].equals("-repack")) { //$NON-NLS-1$
+ options.repack = true;
+ } else if (args[i].equals("-outputDir") && i < args.length - 2) { //$NON-NLS-1$
+ if (args[i + 1].startsWith("-")) { //$NON-NLS-1$
+ printUsage();
+ return null;
+ }
+ options.outputDir = args[++i];
+ } else if (args[i].equals("-verbose")) { //$NON-NLS-1$
+ options.verbose = true;
+ } else if (args[i].equals("-processAll")) { //$NON-NLS-1$
+ options.processAll = true;
+ }
+ }
+
+ options.input = new File(args[i]);
+
+ String problemMessage = null;
+ String inputName = options.input.getName();
+ if (options.unpack) {
+ if (!JarProcessor.canPerformUnpack()) {
+ problemMessage = "The unpack200 command cannot be found."; //$NON-NLS-1$
+ } else if (options.input.isFile() && !inputName.endsWith(".zip") && !inputName.endsWith(".pack.gz")) { //$NON-NLS-1$ //$NON-NLS-2$
+ problemMessage = "Input file is not a pack.gz file."; //$NON-NLS-1$
+ } else if (options.pack || options.repack || options.signCommand != null) {
+ problemMessage = "Pack, repack or sign cannot be specified with unpack."; //$NON-NLS-1$
+ }
+ } else {
+ if (options.input.isFile() && !inputName.endsWith(".zip") && !inputName.endsWith(".jar")) { //$NON-NLS-1$ //$NON-NLS-2$
+ problemMessage = "Input file is not a jar file."; //$NON-NLS-1$
+ } else if ((options.pack || options.repack) && !JarProcessor.canPerformPack()) {
+ problemMessage = "The pack200 command can not be found."; //$NON-NLS-1$
+ }
+ }
+ if(problemMessage != null){
+ System.out.println(problemMessage);
+ System.out.println();
+ printUsage();
+ return null;
+ }
+
+ return options;
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ Options options = processArguments(args);
+ if (options == null)
+ return;
+ new JarProcessorExecutor().runJarProcessor(options);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackStep.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackStep.java
new file mode 100644
index 000000000..1006dbe42
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackStep.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+public class PackStep extends CommandStep {
+
+ protected static String packCommand = null;
+ private static Boolean canPack = null;
+
+ private String arguments = null;
+ private Set exclusions = Collections.EMPTY_SET;
+
+ public static boolean canPack() {
+ if (canPack != null)
+ return canPack.booleanValue();
+
+ String[] locations = Utils.getPack200Commands("pack200"); //$NON-NLS-1$
+ if (locations == null) {
+ canPack = Boolean.FALSE;
+ packCommand = null;
+ return false;
+ }
+
+ int result;
+ for (int i = 0; i < locations.length; i++) {
+ if (locations[i] == null)
+ continue;
+ result = execute(new String[] {locations[i], "-V"}); //$NON-NLS-1$
+ if (result == 0) {
+ packCommand = locations[i];
+ canPack = Boolean.TRUE;
+ return true;
+ }
+ }
+
+ canPack = Boolean.FALSE;
+ return false;
+ }
+
+ public PackStep(Properties options) {
+ super(options, null, null, false);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public PackStep(Properties options, boolean verbose) {
+ super(options, null, null, verbose);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public String recursionEffect(String entryName) {
+ if (canPack() && entryName.endsWith(".jar") && !exclusions.contains(entryName)) { //$NON-NLS-1$
+ return entryName + Utils.PACKED_SUFFIX;
+ }
+ return null;
+ }
+
+ public File preProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ public File postProcess(File input, File workingDirectory, List containers) {
+ if (canPack() && packCommand != null) {
+ Properties inf = Utils.getEclipseInf(input, verbose);
+ if (!shouldPack(input, containers, inf))
+ return null;
+ File outputFile = new File(workingDirectory, input.getName() + Utils.PACKED_SUFFIX);
+ try {
+ String[] cmd = getCommand(input, outputFile, inf, containers);
+ int result = execute(cmd, verbose);
+ if (result != 0 && verbose)
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ return null;
+ }
+ return outputFile;
+ }
+ return null;
+ }
+
+ protected boolean shouldPack(File input, List containers, Properties inf) {
+ //1: exclude by containers
+ // innermost jar is first on the list, it can override outer jars
+ for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+ Properties container = (Properties) iterator.next();
+ if (container.containsKey(Utils.MARK_EXCLUDE_CHILDREN_PACK)) {
+ if (Boolean.valueOf(container.getProperty(Utils.MARK_EXCLUDE_CHILDREN_PACK)).booleanValue()) {
+ if (verbose)
+ System.out.println(input.getName() + " is excluded from pack200 by its containers.");
+ return false;
+ }
+ break;
+ }
+ }
+
+ //2: excluded by self
+ if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
+ if (verbose)
+ System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+
+ return true;
+ }
+
+ protected String[] getCommand(File input, File outputFile, Properties inf, List containers) throws IOException {
+ String[] cmd = null;
+ String arguments = getArguments(input, inf, containers);
+ if (arguments != null && arguments.length() > 0) {
+ String[] args = Utils.toStringArray(arguments, ","); //$NON-NLS-1$
+ cmd = new String[3 + args.length];
+ cmd[0] = packCommand;
+ System.arraycopy(args, 0, cmd, 1, args.length);
+ cmd[cmd.length - 2] = outputFile.getCanonicalPath();
+ cmd[cmd.length - 1] = input.getCanonicalPath();
+ } else {
+ cmd = new String[] {packCommand, outputFile.getCanonicalPath(), input.getCanonicalPath()};
+ }
+ return cmd;
+ }
+
+ protected String getArguments(File input, Properties inf, List containers) {
+ if (arguments != null)
+ return arguments;
+ //1: Explicitly marked in our .inf file
+ if (inf != null && inf.containsKey(Utils.PACK_ARGS)) {
+ arguments = inf.getProperty(Utils.PACK_ARGS);
+ return arguments;
+ }
+
+ //2: Defaults set in one of our containing jars
+ for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+ Properties container = (Properties) iterator.next();
+ if (container.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+ arguments = container.getProperty(Utils.DEFAULT_PACK_ARGS);
+ return arguments;
+ }
+ }
+
+ //3: Set by name in outside pack.properties file
+ Properties options = getOptions();
+ String argsKey = input.getName() + Utils.PACK_ARGS_SUFFIX;
+ if (options.containsKey(argsKey)) {
+ arguments = options.getProperty(argsKey);
+ return arguments;
+ }
+
+ //4: Set by default in outside pack.properties file
+ if (options.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+ arguments = options.getProperty(Utils.DEFAULT_PACK_ARGS);
+ return arguments;
+ }
+
+ if (arguments == null)
+ arguments = "";
+ return arguments;
+ }
+
+ public String getStepName() {
+ return "Pack"; //$NON-NLS-1$
+ }
+
+ public void adjustInf(File input, Properties inf, List containers) {
+ if (input == null || inf == null)
+ return;
+
+ //don't be verbose to check if we should mark the inf
+ boolean v = verbose;
+ verbose = false;
+ if (!shouldPack(input, containers, inf)) {
+ verbose = v;
+ return;
+ }
+ verbose = v;
+
+ //mark as conditioned
+ inf.put(Utils.MARK_PROPERTY, "true"); //$NON-NLS-1$
+
+ //record arguments used
+ String arguments = inf.getProperty(Utils.PACK_ARGS);
+ if (arguments == null) {
+ arguments = getArguments(input, inf, containers);
+ if (arguments != null && arguments.length() > 0)
+ inf.put(Utils.PACK_ARGS, arguments);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackUnpackStep.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackUnpackStep.java
new file mode 100644
index 000000000..79707a69f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/PackUnpackStep.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class PackUnpackStep extends PackStep {
+ private Set exclusions = null;
+
+ public PackUnpackStep(Properties options) {
+ super(options);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public PackUnpackStep(Properties options, boolean verbose) {
+ super(options, verbose);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public String recursionEffect(String entryName) {
+ if (canPack() && entryName.endsWith(".jar") && !exclusions.contains(entryName)) { //$NON-NLS-1$
+ return entryName;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.internal.jarprocessor.PackStep#postProcess(java.io.File, java.io.File, java.util.LinkedList)
+ */
+ public File postProcess(File input, File workingDirectory, List containers) {
+ if (canPack() && packCommand != null && input != null) {
+ Properties inf = Utils.getEclipseInf(input, verbose);
+ if (!shouldPack(input, containers, inf))
+ return null;
+ File tempFile = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
+ try {
+ String[] tmp = getCommand(input, tempFile, inf, containers);
+ String[] cmd = new String[tmp.length + 1];
+ cmd[0] = tmp[0];
+ cmd[1] = "-r"; //$NON-NLS-1$
+ System.arraycopy(tmp, 1, cmd, 2, tmp.length - 1);
+
+ int result = execute(cmd, verbose);
+ if (result == 0 && tempFile.exists()) {
+ File finalFile = new File(workingDirectory, input.getName());
+ if (finalFile.exists())
+ finalFile.delete();
+ tempFile.renameTo(finalFile);
+ return finalFile;
+ } else if (verbose) {
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.internal.jarprocessor.PackStep#preProcess(java.io.File, java.io.File, java.util.LinkedList)
+ */
+ public File preProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ public String getStepName() {
+ return "Repack"; //$NON-NLS-1$
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/SignCommandStep.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/SignCommandStep.java
new file mode 100644
index 000000000..b8c6ec091
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/SignCommandStep.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+public class SignCommandStep extends CommandStep {
+ private Set exclusions = null;
+
+ public SignCommandStep(Properties options, String command) {
+ super(options, command, ".jar", false); //$NON-NLS-1$
+ exclusions = Utils.getSignExclusions(options);
+ }
+
+ public SignCommandStep(Properties options, String command, boolean verbose) {
+ super(options, command, ".jar", verbose); //$NON-NLS-1$
+ exclusions = Utils.getSignExclusions(options);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#recursionEffect(java.lang.String)
+ */
+ public String recursionEffect(String entryName) {
+ if (entryName.endsWith(extension) && !exclusions.contains(entryName))
+ return entryName;
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
+ */
+ public File preProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
+ */
+ public File postProcess(File input, File workingDirectory, List containers) {
+ if (command != null && input != null && shouldSign(input, containers)) {
+ try {
+ String[] cmd = new String[] {command, input.getCanonicalPath()};
+ int result = execute(cmd, verbose);
+ if (result == 0) {
+ return input;
+ } else if (verbose) {
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ } catch (IOException e) {
+ if (verbose) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return null;
+ }
+
+ public boolean shouldSign(File input, List containers) {
+ Properties inf = null;
+
+ //1: Are we excluded from signing by our parents?
+ //innermost jar is first on the list, it overrides outer jars
+ for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+ inf = (Properties) iterator.next();
+ if (inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN_SIGN)){
+ if(Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN_SIGN)).booleanValue()) {
+ if (verbose)
+ System.out.println(input.getName() + "is excluded from signing by its containers."); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+ break;
+ }
+ }
+
+ //2: Is this jar itself marked as exclude?
+ inf = Utils.getEclipseInf(input, verbose);
+ if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_SIGN) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_SIGN)).booleanValue()) {
+ if (verbose)
+ System.out.println("Excluding " + input.getName() + " from signing."); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+ return true;
+ }
+
+ public String getStepName() {
+ return "Sign"; //$NON-NLS-1$
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/StreamProcessor.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/StreamProcessor.java
new file mode 100644
index 000000000..cdab81291
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/StreamProcessor.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.*;
+
+public class StreamProcessor extends Thread {
+ public static final String STDERR = "STDERR"; //$NON-NLS-1$
+ public static final String STDOUT = "STDOUT"; //$NON-NLS-1$
+
+ private InputStream inputStream;
+ private String name;
+ private boolean verbose;
+
+ public StreamProcessor(InputStream is, String name, boolean verbose) {
+ this.inputStream = is;
+ this.name = name;
+ this.verbose = verbose;
+ }
+
+ public void run() {
+ try {
+ InputStreamReader isr = new InputStreamReader(inputStream);
+ BufferedReader br = new BufferedReader(isr);
+ while (true) {
+ String s = br.readLine();
+ if (s == null) {
+ break;
+ }
+ if (verbose) {
+ if (STDERR.equals(name))
+ System.err.println(name + ": " + s); //$NON-NLS-1$
+ else
+ System.out.println(name + ": " + s); //$NON-NLS-1$
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/UnpackStep.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/UnpackStep.java
new file mode 100644
index 000000000..276d78d59
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/UnpackStep.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author aniefer
+ *
+ */
+public class UnpackStep extends CommandStep {
+ public static final String UNPACKER_PROPERTY = "org.eclipse.update.jarprocessor.Unpacker"; //$NON-NLS-1$
+ private static Boolean canUnpack = null;
+ private static String unpackCommand = null;
+
+ public static boolean canUnpack() {
+ if (canUnpack != null)
+ return canUnpack.booleanValue();
+
+ String[] locations = Utils.getPack200Commands("unpack200"); //$NON-NLS-1$
+ if (locations == null) {
+ canUnpack = Boolean.FALSE;
+ unpackCommand = null;
+ return false;
+ }
+
+ int result;
+ for (int i = 0; i < locations.length; i++) {
+ if (locations[i] == null)
+ continue;
+ result = execute(new String[] {locations[i], "-V"}); //$NON-NLS-1$
+ if (result == 0) {
+ unpackCommand = locations[i];
+ canUnpack = Boolean.TRUE;
+ return true;
+ }
+ }
+
+ canUnpack = Boolean.FALSE;
+ return false;
+ }
+
+ public UnpackStep(Properties options) {
+ super(options, null, null, false);
+ }
+
+ public UnpackStep(Properties options, boolean verbose) {
+ super(options, null, null, verbose);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#recursionEffect(java.lang.String)
+ */
+ public String recursionEffect(String entryName) {
+ if (canUnpack() && entryName.endsWith(Utils.PACKED_SUFFIX)) {
+ return entryName.substring(0, entryName.length() - Utils.PACKED_SUFFIX.length());
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
+ */
+ public File preProcess(File input, File workingDirectory, List containers) {
+ if (canUnpack() && unpackCommand != null) {
+ String name = input.getName();
+ if (name.endsWith(Utils.PACKED_SUFFIX)) {
+ name = name.substring(0, name.length() - Utils.PACKED_SUFFIX.length());
+
+ File unpacked = new File(workingDirectory, name);
+ File parent = unpacked.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ try {
+ String options = getOptions().getProperty(input.getName() + ".unpack.args"); //$NON-NLS-1$
+ String[] cmd = null;
+ if (options != null) {
+ cmd = new String[] {unpackCommand, options, input.getCanonicalPath(), unpacked.getCanonicalPath()};
+ } else {
+ cmd = new String[] {unpackCommand, input.getCanonicalPath(), unpacked.getCanonicalPath()};
+ }
+ int result = execute(cmd, verbose);
+ if (result != 0 && verbose)
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ return null;
+ }
+ return unpacked;
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
+ */
+ public File postProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ public String getStepName() {
+ return "Unpack"; //$NON-NLS-1$
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Utils.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Utils.java
new file mode 100644
index 000000000..744e92f6d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/Utils.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipException;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class Utils {
+ public static final String MARK_FILE_NAME = "META-INF/eclipse.inf"; //$NON-NLS-1$
+
+ /*
+ * Properties found in outer pack.properties file
+ */
+ //comma separated list of jars to exclude from sigining
+ public static final String SIGN_EXCLUDES = "sign.excludes"; //$NON-NLS-1$
+ //comma separated list of jars to exlclude from packing
+ public static final String PACK_EXCLUDES = "pack.excludes"; //$NON-NLS-1$
+ //Suffix used when specifying arguments to use when running pack200 on a jar
+ public static final String PACK_ARGS_SUFFIX = ".pack.args"; //$NON-NLS-1$
+
+ /*
+ * Properties found in both pack.properties and eclipse.inf
+ */
+ // Default arguments to use when running pack200.
+ // Affects all jars when specified in pack.properties, affects children when specified in eclipse.inf
+ public static final String DEFAULT_PACK_ARGS = "pack200.default.args"; //$NON-NLS-1$
+
+ /*
+ * Properties found in eclipse.inf file
+ */
+ //This jar has been conditioned with pack200
+ public static final String MARK_PROPERTY = "pack200.conditioned"; //$NON-NLS-1$
+ //Exclude this jar from processing
+ public static final String MARK_EXCLUDE = "jarprocessor.exclude"; //$NON-NLS-1$
+ //Exclude this jar from pack200
+ public static final String MARK_EXCLUDE_PACK = "jarprocessor.exclude.pack"; //$NON-NLS-1$
+ //Exclude this jar from signing
+ public static final String MARK_EXCLUDE_SIGN = "jarprocessor.exclude.sign"; //$NON-NLS-1$
+ //Exclude this jar's children from processing
+ public static final String MARK_EXCLUDE_CHILDREN = "jarprocessor.exclude.children";
+ //Exclude this jar's children from pack200
+ public static final String MARK_EXCLUDE_CHILDREN_PACK = "jarprocessor.exclude.children.pack";
+ //Exclude this jar's children from signing
+ public static final String MARK_EXCLUDE_CHILDREN_SIGN = "jarprocessor.exclude.children.sign";
+ //Arguments used in pack200 for this jar
+ public static final String PACK_ARGS = "pack200.args"; //$NON-NLS-1$
+
+ public static final String PACK200_PROPERTY = "org.eclipse.update.jarprocessor.pack200"; //$NON-NLS-1$
+ public static final String JRE = "@jre"; //$NON-NLS-1$
+ public static final String PATH = "@path"; //$NON-NLS-1$
+ public static final String NONE = "@none"; //$NON-NLS-1$
+
+ public static final String PACKED_SUFFIX = ".pack.gz"; //$NON-NLS-1$
+ public static final String JAR_SUFFIX = ".jar"; //$NON-NLS-1$
+
+ public static final FileFilter JAR_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isFile() && pathname.getName().endsWith(".jar"); //$NON-NLS-1$
+ }
+ };
+
+ public static final FileFilter PACK_GZ_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isFile() && pathname.getName().endsWith(PACKED_SUFFIX);
+ }
+ };
+
+ public static void close(Object stream) {
+ if (stream != null) {
+ try {
+ if (stream instanceof InputStream)
+ ((InputStream) stream).close();
+ else if (stream instanceof OutputStream)
+ ((OutputStream) stream).close();
+ else if (stream instanceof JarFile)
+ ((JarFile) stream).close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * get the set of commands to try to execute pack/unpack
+ * @param cmd the command, either "pack200" or "unpack200"
+ * @return String [] or null
+ */
+ public static String[] getPack200Commands(String cmd) {
+ String[] locations = null;
+ String prop = System.getProperty(PACK200_PROPERTY);
+ String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
+ if (NONE.equals(prop)) {
+ return null;
+ } else if (JRE.equals(prop)) {
+ locations = new String[] {javaHome + "/bin/" + cmd}; //$NON-NLS-1$
+ } else if (PATH.equals(prop)) {
+ locations = new String[] {cmd};
+ } else if (prop == null) {
+ locations = new String[] {javaHome + "/bin/" + cmd, cmd}; //$NON-NLS-1$
+ } else {
+ locations = new String[] {prop + "/" + cmd}; //$NON-NLS-1$
+ }
+ return locations;
+ }
+
+ /**
+ * Transfers all available bytes from the given input stream to the given
+ * output stream. Closes both streams if close == true, regardless of failure.
+ * Flushes the destination stream if close == false
+ *
+ * @param source
+ * @param destination
+ * @param close
+ * @throws IOException
+ */
+ public static void transferStreams(InputStream source, OutputStream destination, boolean close) throws IOException {
+ source = new BufferedInputStream(source);
+ destination = new BufferedOutputStream(destination);
+ try {
+ byte[] buffer = new byte[8192];
+ while (true) {
+ int bytesRead = -1;
+ if ((bytesRead = source.read(buffer)) == -1)
+ break;
+ destination.write(buffer, 0, bytesRead);
+ }
+ } finally {
+ if (close) {
+ close(source);
+ close(destination);
+ } else {
+ destination.flush();
+ }
+ }
+ }
+
+ /**
+ * Deletes all the files and directories from the given root down (inclusive).
+ * Returns false if we could not delete some file or an exception occurred
+ * at any point in the deletion.
+ * Even if an exception occurs, a best effort is made to continue deleting.
+ */
+ public static boolean clear(java.io.File root) {
+ boolean result = clearChildren(root);
+ try {
+ if (root.exists())
+ result &= root.delete();
+ } catch (Exception e) {
+ result = false;
+ }
+ return result;
+ }
+
+ /**
+ * Deletes all the files and directories from the given root down, except for
+ * the root itself.
+ * Returns false if we could not delete some file or an exception occurred
+ * at any point in the deletion.
+ * Even if an exception occurs, a best effort is made to continue deleting.
+ */
+ public static boolean clearChildren(java.io.File root) {
+ boolean result = true;
+ if (root.isDirectory()) {
+ String[] list = root.list();
+ // for some unknown reason, list() can return null.
+ // Just skip the children If it does.
+ if (list != null)
+ for (int i = 0; i < list.length; i++)
+ result &= clear(new java.io.File(root, list[i]));
+ }
+ return result;
+ }
+
+ public static Set getPackExclusions(Properties properties) {
+ if (properties == null)
+ return Collections.EMPTY_SET;
+
+ String packExcludes = properties.getProperty(PACK_EXCLUDES);
+ if (packExcludes != null) {
+ String[] excludes = toStringArray(packExcludes, ","); //$NON-NLS-1$
+ Set packExclusions = new HashSet();
+ for (int i = 0; i < excludes.length; i++) {
+ packExclusions.add(excludes[i]);
+ }
+ return packExclusions;
+ }
+ return Collections.EMPTY_SET;
+ }
+
+ public static Set getSignExclusions(Properties properties) {
+ if (properties == null)
+ return Collections.EMPTY_SET;
+ String signExcludes = properties.getProperty(SIGN_EXCLUDES);
+ if (signExcludes != null) {
+ String[] excludes = toStringArray(signExcludes, ","); //$NON-NLS-1$
+ Set signExclusions = new HashSet();
+ for (int i = 0; i < excludes.length; i++) {
+ signExclusions.add(excludes[i]);
+ }
+ return signExclusions;
+ }
+ return Collections.EMPTY_SET;
+ }
+
+ public static String concat(String[] array) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0)
+ buffer.append(' ');
+ buffer.append(array[i]);
+ }
+ return buffer.toString();
+ }
+
+ public static String[] toStringArray(String input, String separator) {
+ StringTokenizer tokenizer = new StringTokenizer(input, separator);
+ int count = tokenizer.countTokens();
+ String[] result = new String[count];
+ for (int i = 0; i < count; i++) {
+ result[i] = tokenizer.nextToken().trim();
+ }
+ return result;
+ }
+
+ /**
+ * Get the properties from the eclipse.inf file from the given jar. If the file is not a jar, null is returned.
+ * If the file is a jar, but does not contain an eclipse.inf file, an empty Properties object is returned.
+ * @param jarFile
+ * @return The eclipse.inf properties for the given jar file
+ */
+ public static Properties getEclipseInf(File jarFile, boolean verbose) {
+ if (jarFile == null || !jarFile.exists()) {
+ if (verbose)
+ System.out.println("Failed to obtain eclipse.inf due to missing jar file: " + jarFile);
+ return null;
+ }
+ JarFile jar = null;
+ try {
+ jar = new JarFile(jarFile, false);
+ } catch (ZipException e) {
+ //not a jar, don't bother logging this.
+ return null;
+ } catch (IOException e) {
+ if (verbose) {
+ System.out.println("Failed to obtain eclipse.inf due to IOException: " + jarFile);
+ e.printStackTrace();
+ }
+ return null;
+ }
+ try {
+ JarEntry mark = jar.getJarEntry(MARK_FILE_NAME);
+ if (mark != null) {
+ InputStream in = jar.getInputStream(mark);
+ Properties props = new Properties();
+ props.load(in);
+ in.close();
+ return props;
+ }
+ return new Properties();
+ } catch (IOException e) {
+ if (verbose) {
+ System.out.println("Failed to obtain eclipse.inf due to IOException: " + jarFile);
+ e.printStackTrace();
+ }
+ return null;
+ } finally {
+ close(jar);
+ }
+ }
+
+ public static boolean shouldSkipJar(File input, boolean processAll, boolean verbose) {
+ Properties inf = getEclipseInf(input, verbose);
+ if (inf == null) {
+ //not a jar, could be a pack.gz
+ return false;
+ }
+ String exclude = inf.getProperty(MARK_EXCLUDE);
+
+ //was marked as exclude, we should skip
+ if (exclude != null && Boolean.valueOf(exclude).booleanValue())
+ return true;
+
+ //process all was set, don't skip
+ if (processAll)
+ return false;
+
+ //otherwise, we skip if not marked marked
+ String marked = inf.getProperty(MARK_PROPERTY);
+ return !Boolean.valueOf(marked).booleanValue();
+ }
+
+ /**
+ * Stores the given properties in the output stream. We store the properties
+ * in sorted order so that the signing hash doesn't change if the properties didn't change.
+ * @param props
+ * @param stream
+ */
+ public static void storeProperties(Properties props, OutputStream stream) {
+ PrintStream printStream = new PrintStream(stream);
+ printStream.print("#Processed using Jarprocessor\n"); //$NON-NLS-1$
+ SortedMap sorted = new TreeMap(props);
+ for (Iterator iter = sorted.keySet().iterator(); iter.hasNext();) {
+ String key = (String) iter.next();
+ printStream.print(key);
+ printStream.print(" = "); //$NON-NLS-1$
+ printStream.print(sorted.get(key));
+ printStream.print("\n");
+
+ }
+ printStream.flush();
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/ZipProcessor.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/ZipProcessor.java
new file mode 100644
index 000000000..6278a7775
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/ZipProcessor.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.jarprocessor;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+import org.eclipse.equinox.p2.jarprocessor.IProcessStep;
+import org.eclipse.equinox.p2.jarprocessor.JarProcessor;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class ZipProcessor {
+
+ private IProcessStep signStep = null;
+ private IProcessStep packStep = null;
+ private IProcessStep packUnpackStep = null;
+ private IProcessStep unpackStep = null;
+
+ private String workingDirectory = null;
+ private Properties properties = null;
+ private Set packExclusions = null;
+ private Set signExclusions = null;
+ private String command = null;
+ private boolean packing = false;
+ private boolean signing = false;
+ private boolean repacking = false;
+ private boolean unpacking = false;
+ private boolean verbose = false;
+ private boolean processAll = false;
+
+ public void setWorkingDirectory(String dir) {
+ workingDirectory = dir;
+ }
+
+ public String getWorkingDirectory() {
+ if (workingDirectory == null)
+ workingDirectory = "."; //$NON-NLS-1$
+ return workingDirectory;
+ }
+
+ public void setSignCommand(String command) {
+ this.command = command;
+ this.signing = (command != null);
+ }
+
+ public void setPack(boolean pack) {
+ this.packing = pack;
+ }
+
+ public void setRepack(boolean repack) {
+ this.repacking = repack;
+ }
+
+ public void setUnpack(boolean unpack) {
+ this.unpacking = unpack;
+ }
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public void setProcessAll(boolean all) {
+ this.processAll = all;
+ }
+
+ public void processZip(File zipFile) throws ZipException, IOException {
+ if (verbose)
+ System.out.println("Processing " + zipFile.getPath()); //$NON-NLS-1$
+ ZipFile zip = new ZipFile(zipFile);
+ initialize(zip);
+
+ String extension = unpacking ? "pack.gz" : ".jar"; //$NON-NLS-1$ //$NON-NLS-2$
+ File tempDir = new File(getWorkingDirectory(), "temp_" + zipFile.getName()); //$NON-NLS-1$
+ JarProcessor processor = new JarProcessor();
+ processor.setVerbose(verbose);
+ processor.setProcessAll(processAll);
+ processor.setWorkingDirectory(tempDir.getCanonicalPath());
+ if (unpacking) {
+ processor.addProcessStep(unpackStep);
+ }
+
+ File outputFile = new File(getWorkingDirectory(), zipFile.getName() + ".temp"); //$NON-NLS-1$
+ File parent = outputFile.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(outputFile));
+ Enumeration entries = zip.entries();
+ if (entries.hasMoreElements()) {
+ for (ZipEntry entry = (ZipEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (ZipEntry) entries.nextElement() : null) {
+ String name = entry.getName();
+
+ InputStream entryStream = zip.getInputStream(entry);
+
+ boolean pack = packing && !packExclusions.contains(name);
+ boolean sign = signing && !signExclusions.contains(name);
+ boolean repack = repacking && !packExclusions.contains(name);
+
+ File extractedFile = null;
+
+ if (entry.getName().endsWith(extension) && (pack || sign || repack || unpacking)) {
+ extractedFile = new File(tempDir, name);
+ parent = extractedFile.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ if (verbose)
+ System.out.println("Extracting " + entry.getName()); //$NON-NLS-1$
+ FileOutputStream extracted = new FileOutputStream(extractedFile);
+ Utils.transferStreams(entryStream, extracted, true); // this will close the stream
+ entryStream = null;
+
+ boolean skip = Utils.shouldSkipJar(extractedFile, processAll, verbose);
+ if (skip) {
+ //skipping this file
+ entryStream = new FileInputStream(extractedFile);
+ if (verbose)
+ System.out.println(entry.getName() + " is not marked, skipping."); //$NON-NLS-1$
+ } else {
+ if (unpacking) {
+ File result = processor.processJar(extractedFile);
+ name = name.substring(0, name.length() - extractedFile.getName().length()) + result.getName();
+ extractedFile = result;
+ } else {
+ if (repack || sign) {
+ processor.clearProcessSteps();
+ if (repack)
+ processor.addProcessStep(packUnpackStep);
+ if (sign)
+ processor.addProcessStep(signStep);
+ extractedFile = processor.processJar(extractedFile);
+ }
+ if (pack) {
+ processor.clearProcessSteps();
+ processor.addProcessStep(packStep);
+ File modifiedFile = processor.processJar(extractedFile);
+ if (modifiedFile.exists()) {
+ try {
+ String newName = name.substring(0, name.length() - extractedFile.getName().length()) + modifiedFile.getName();
+ if (verbose) {
+ System.out.println("Adding " + newName + " to " + outputFile.getPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ System.out.println();
+ }
+ ZipEntry zipEntry = new ZipEntry(newName);
+ entryStream = new FileInputStream(modifiedFile);
+ zipOut.putNextEntry(zipEntry);
+ Utils.transferStreams(entryStream, zipOut, false); //we want to keep zipOut open
+ entryStream.close();
+ Utils.clear(modifiedFile);
+ } catch (IOException e) {
+ Utils.close(entryStream);
+ if (verbose) {
+ e.printStackTrace();
+ System.out.println("Warning: Problem reading " + modifiedFile.getPath() + ".");
+ }
+ }
+ entryStream = null;
+ } else if (verbose) {
+ System.out.println("Warning: " + modifiedFile.getPath() + " not found.");
+ }
+ }
+ }
+ if (extractedFile.exists()) {
+ try {
+ entryStream = new FileInputStream(extractedFile);
+ } catch (IOException e) {
+ if (verbose) {
+ e.printStackTrace();
+ System.out.println("Warning: Problem reading " + extractedFile.getPath() + ".");
+ }
+ }
+ }
+
+ if (verbose && entryStream != null) {
+ System.out.println("Adding " + name + " to " + outputFile.getPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ if (entryStream != null) {
+ ZipEntry newEntry = new ZipEntry(name);
+ try {
+ zipOut.putNextEntry(newEntry);
+ Utils.transferStreams(entryStream, zipOut, false);
+ zipOut.closeEntry();
+ } catch (ZipException e) {
+ if(verbose) {
+ System.out.println("Warning: " + name + " already exists in " + outputFile.getName() + ". Skipping.");
+ }
+ }
+ entryStream.close();
+ }
+
+ if (extractedFile != null)
+ Utils.clear(extractedFile);
+
+ if (verbose) {
+ System.out.println();
+ System.out.println("Processing " + zipFile.getPath()); //$NON-NLS-1$
+ }
+ }
+ }
+ zipOut.close();
+ zip.close();
+
+ File finalFile = new File(getWorkingDirectory(), zipFile.getName());
+ if (finalFile.exists())
+ finalFile.delete();
+ outputFile.renameTo(finalFile);
+ Utils.clear(tempDir);
+ }
+
+ private void initialize(ZipFile zip) {
+ ZipEntry entry = zip.getEntry("pack.properties"); //$NON-NLS-1$
+ properties = new Properties();
+ if (entry != null) {
+ InputStream stream = null;
+ try {
+ stream = zip.getInputStream(entry);
+ properties.load(stream);
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ } finally {
+ Utils.close(stream);
+ }
+ }
+
+ packExclusions = Utils.getPackExclusions(properties);
+ signExclusions = Utils.getSignExclusions(properties);
+
+ packUnpackStep = new PackUnpackStep(properties, verbose);
+ packStep = new PackStep(properties, verbose);
+ signStep = new SignCommandStep(properties, command, verbose);
+ unpackStep = new UnpackStep(properties, verbose);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/pack-readme.html b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/pack-readme.html
new file mode 100644
index 000000000..ef5fe5e0b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/internal/p2/jarprocessor/pack-readme.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>Eclipse update packing tool readme</title>
+</head>
+<body>
+<h1>Eclipse update packing tool</h1>
+
+<h3>Overview</h3>
+The update packing tool processes a hierarchy of arbitrarily nested
+JARs and ZIP files. It is a generic utility that performs a depth first traversal of
+a nested hierarchy of ZIPs and JARs, performs various commands on
+each of the JARs in the hierarchy, and then rebuilds the same hierarchy
+of ZIPs and JARs again. Currently its main functions are:
+<ul>
+ <li>Packing JARs using the Java 1.5 <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/pack200.html">pack200</a>
+ command.</li>
+ <li>Unpacking PACK.GZs using the Java 1.5 <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/unpack200.html">unpack200</a>
+ command.</li>
+ <li>Normalizing JARs for future compression by pack200. This is accomplished
+ by running the pack200 command with the <tt>--repack</tt> command line argument.</li>
+ <li>Signing JARs to allow for authentication of the origin of JARs. This is accomplished by
+ running a supplied command (typically the command will just be a wrapper around
+ the Java <a href="http://java.sun.com/j2se/1.3/docs/tooldocs/win32/jarsigner.html">jarsigner</a> tool).</li>
+</ul>
+The packing tool is used in the following contexts:
+<ul>
+ <li>During a PDE build, to prepare JARs for uploading to an Eclipse
+ update site. In this usage, it is used to both nomalize JAR contents
+ (pack200 -repack), and sign JARs.</li>
+ <li>On an update site, to convert traditional JAR content into the
+ compressed pack200 format.</li>
+ <li>From an Eclipse client application during update, to convert
+ compressed pack200 format content into executable JAR files.</li>
+</ul>
+<h3>Tool usage</h3>
+To run the packing tool, you need a 1.5 JRE installed. The tool is run
+by invoking Java as follows:
+
+<pre>
+ java jarprocessor.jar [options] input
+</pre>
+
+Where <tt>input</tt> is either a zip file, a directory, or a JAR (or a pack.gz file). All files ending
+in ".jar" or ".pack.gz" in the provided zip or directory hierarchy
+will be processed.
+The following additional command line arguments are supported:
+<ul>
+<li>-repack : Normalize the jars using pack200 <tt>--repack</tt></li>
+<li>-sign &lt;cmd&gt; : signs the jars by executing the provided command.
+The command will be provided a single argument that will be the full path of the JAR to process.
+</li>
+<li>-pack : for each input in JAR form, produce a corresponding output
+in packed form. For an input "a.jar", the output is a.jar.pack.gz.
+</li>
+<li>-unpack : for each input in packed form, produce a corresponding output
+in unpacked form. For an input "a.jar.pack.gz", the output is "a.jar". -unpack is mutually exclusive with -repack, -pack and -sign.</li>
+<li>-outputDir &lt;dir&gt; : The directory to put the tool's output into. If the input was a zip file, then an output zip file will be
+created containg all the output files. If the input was a directory, for each input file there is a corresponding output file in the output directory. By default the current working directory is used. If the input is in the same
+directory as the output, the input files may be overwritten.</li>
+</ul>
+
+Additionally, when the input is a zip file, it may contain a file called
+<tt>pack.properties</tt>. The pack.properties file supports the following values:
+<ul>
+<li>pack.excludes = jarName[, jarName]* : A comma-delimited list of JARs that should not be packed or repacked.
+</li>
+<li>sign.excludes = jarName[, jarName]* : A comma-delimited list of JARs that should not be signed.
+</li>
+<li>&lt;jarname&gt;.pack.args = option[, option]* : A comma-delimited list of additional arguments that should
+be passed to pack200 when packing any jar with name &lt;jarname&gt;.
+</ul>
+</p>
+<p>
+<font size=-1>
+Copyright (c) IBM Corporation and others 2006. All rights reserved. This program and the accompanying materials
+are made available under the terms of the
+<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License v1.0</a>.
+</font>
+</body>
+</html>
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/IProcessStep.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/IProcessStep.java
new file mode 100644
index 000000000..d5d0ba7ef
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/IProcessStep.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.p2.jarprocessor;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public interface IProcessStep {
+
+ /**
+ * The effect of this processing step if the JarProcessor was to recurse on this entry.
+ * Return null if this step will not do anything with this entry.
+ * Return the new entryName if this step will modify this entry on recursion.
+ * @param entryName
+ * @return
+ */
+ public String recursionEffect(String entryName);
+
+ /**
+ * Perform some processing on the input file before the JarProcessor considers the entries for recursion.
+ * return the file containing the result of the processing
+ * @param input
+ * @param workingDirectory
+ * @param containers inf properties for containing jars, innermost jar is first on the list
+ * @return
+ */
+ public File preProcess(File input, File workingDirectory, List containers);
+
+ /**
+ * Perform some processing on the input file after the JarProcessor returns from recursion
+ * return the file containing the result of the processing
+ * @param input
+ * @param workingDirectory
+ * @param containers inf properties for containing jars, innermost jar is first on the list
+ * @return
+ */
+ public File postProcess(File input, File workingDirectory, List containers);
+
+ /**
+ * Return the name of this process step
+ * @return
+ */
+ public String getStepName();
+
+ /**
+ * Adjust any properties in the eclipse.inf as appropriate for this step
+ * @param input
+ * @param inf
+ * @param containers inf properties for containing jars, innermost jar is first on the list
+ */
+ public void adjustInf(File input, Properties inf, List containers);
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessor.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessor.java
new file mode 100644
index 000000000..fbaa7c7f9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessor.java
@@ -0,0 +1,394 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.p2.jarprocessor;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import org.eclipse.equinox.internal.p2.jarprocessor.*;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class JarProcessor {
+ private List steps = new ArrayList();
+ private String workingDirectory = ""; //$NON-NLS-1$
+ private int depth = -1;
+ private boolean verbose = false;
+ private boolean processAll = false;
+ private LinkedList containingInfs = new LinkedList();
+
+ static public JarProcessor getUnpackProcessor(Properties properties) {
+ if (!canPerformUnpack())
+ throw new UnsupportedOperationException();
+ JarProcessor processor = new JarProcessor();
+ processor.addProcessStep(new UnpackStep(properties));
+ return processor;
+ }
+
+ static public JarProcessor getPackProcessor(Properties properties) {
+ if (!canPerformPack())
+ throw new UnsupportedOperationException();
+ JarProcessor processor = new JarProcessor();
+ processor.addProcessStep(new PackStep(properties));
+ return processor;
+ }
+
+ static public boolean canPerformPack() {
+ return PackStep.canPack();
+ }
+
+ static public boolean canPerformUnpack() {
+ return UnpackStep.canUnpack();
+ }
+
+ public String getWorkingDirectory() {
+ return workingDirectory;
+ }
+
+ public void setWorkingDirectory(String dir) {
+ if(dir != null)
+ workingDirectory = dir;
+ }
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public void setProcessAll(boolean all){
+ this.processAll = all;
+ }
+
+ public void addProcessStep(IProcessStep step) {
+ steps.add(step);
+ }
+
+ public void clearProcessSteps() {
+ steps.clear();
+ }
+
+ /**
+ * Recreate a jar file. The replacements map specifies entry names to be replaced, the replacements are
+ * expected to be found in directory.
+ *
+ * @param jar - The input jar
+ * @param outputJar - the output
+ * @param replacements - map of entryName -> new entryName
+ * @param directory - location to find file for new entryName
+ * @throws IOException
+ */
+ private void recreateJar(JarFile jar, JarOutputStream outputJar, Map replacements, File directory, Properties inf) throws IOException {
+ InputStream in = null;
+ boolean marked = false;
+ try {
+ Enumeration entries = jar.entries();
+ for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
+ File replacement = null;
+ JarEntry newEntry = null;
+ if (replacements.containsKey(entry.getName())) {
+ String name = (String) replacements.get(entry.getName());
+ replacement = new File(directory, name);
+ if (name != null) {
+ if (replacement.exists()) {
+ try {
+ in = new BufferedInputStream(new FileInputStream(replacement));
+ newEntry = new JarEntry(name);
+ } catch (Exception e) {
+ if (verbose) {
+ e.printStackTrace();
+ System.out.println("Warning: Problem reading " +replacement.getPath() + ", using " + jar.getName() + File.separator + entry.getName() + " instead.");
+ }
+ }
+ } else if (verbose) {
+ System.out.println("Warning: " + replacement.getPath() + " not found, using " + jar.getName() + File.separator + entry.getName() + " instead.");
+ }
+ }
+ }
+ if (newEntry == null) {
+ try {
+ in = new BufferedInputStream(jar.getInputStream(entry));
+ newEntry = new JarEntry(entry.getName());
+ } catch( Exception e ) {
+ if(verbose) {
+ e.printStackTrace();
+ System.out.println("ERROR: problem reading " + entry.getName() + " from " + jar.getName());
+ }
+ continue;
+ }
+ }
+ newEntry.setTime(entry.getTime());
+ outputJar.putNextEntry(newEntry);
+ if (entry.getName().equals(Utils.MARK_FILE_NAME)) {
+ //The eclipse.inf file was read in earlier, don't need to reread it, just write it out now
+ Utils.storeProperties(inf, outputJar);
+ marked = true;
+ } else {
+ Utils.transferStreams(in, outputJar, false);
+ }
+ outputJar.closeEntry();
+ in.close();
+
+ //delete the nested jar file
+ if (replacement != null) {
+ replacement.delete();
+ }
+ }
+ if (!marked) {
+ JarEntry entry = new JarEntry(Utils.MARK_FILE_NAME);
+ outputJar.putNextEntry(entry);
+ Utils.storeProperties(inf, outputJar);
+ outputJar.closeEntry();
+ }
+ } finally {
+ Utils.close(outputJar);
+ Utils.close(jar);
+ Utils.close(in);
+ }
+ }
+
+ private String recursionEffect(String entryName) {
+ String result = null;
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+
+ result = step.recursionEffect(entryName);
+ if (result != null)
+ entryName = result;
+ }
+ return result;
+ }
+
+ private void extractEntries(JarFile jar, File tempDir, Map data, Properties inf) throws IOException {
+ if(inf != null ) {
+ //skip if excluding children
+ if(inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN)){
+ String excludeChildren = inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN);
+ if( Boolean.valueOf(excludeChildren).booleanValue() )
+ if(verbose){
+ for(int i = 0; i <= depth; i++)
+ System.out.print(" "); //$NON-NLS-1$
+ System.out.println("Children of " + jar.getName() + "are excluded from processing.");
+ }
+ return;
+ }
+ }
+
+ Enumeration entries = jar.entries();
+ if (entries.hasMoreElements()) {
+ for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
+ String name = entry.getName();
+ String newName = recursionEffect(name);
+ if (newName != null) {
+ if(verbose){
+ for(int i = 0; i <= depth; i++)
+ System.out.print(" "); //$NON-NLS-1$
+ System.out.println("Processing nested file: " + name); //$NON-NLS-1$
+ }
+ //extract entry to temp directory
+ File extracted = new File(tempDir, name);
+ File parentDir = extracted.getParentFile();
+ if (!parentDir.exists())
+ parentDir.mkdirs();
+
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = jar.getInputStream(entry);
+ out = new BufferedOutputStream(new FileOutputStream(extracted));
+ Utils.transferStreams(in, out, true); //this will close both streams
+ } finally {
+ Utils.close(in);
+ Utils.close(out);
+ }
+ extracted.setLastModified(entry.getTime());
+
+ //recurse
+ containingInfs.addFirst(inf);
+ String dir = getWorkingDirectory();
+ setWorkingDirectory(parentDir.getCanonicalPath());
+ File result = processJar(extracted);
+
+ newName = name.substring(0, name.length() - extracted.getName().length()) + result.getName();
+ data.put(name, newName);
+
+ setWorkingDirectory(dir);
+ containingInfs.removeFirst();
+
+ //delete the extracted item leaving the recursion result
+ if (!name.equals(newName))
+ extracted.delete();
+ }
+ }
+ }
+ }
+
+ private File preProcess(File input, File tempDir) {
+ File result = null;
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ result = step.preProcess(input, tempDir, containingInfs);
+ if (result != null)
+ input = result;
+ }
+ return input;
+ }
+
+ private File postProcess(File input, File tempDir) {
+ File result = null;
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ result = step.postProcess(input, tempDir, containingInfs);
+ if (result != null)
+ input = result;
+ }
+ return input;
+ }
+
+ private void adjustInf(File input, Properties inf) {
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ step.adjustInf(input, inf, containingInfs);
+ }
+ }
+
+ public File processJar(File input) throws IOException {
+ ++depth;
+ long lastModified = input.lastModified();
+ File workingDir = new File(getWorkingDirectory());
+ if (!workingDir.exists())
+ workingDir.mkdirs();
+
+ boolean skip = Utils.shouldSkipJar(input, processAll, verbose);
+ if (depth == 0 && verbose) {
+ if (skip)
+ System.out.println("Skipping " + input.getPath()); //$NON-NLS-1$
+ else {
+ System.out.print("Running "); //$NON-NLS-1$
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ System.out.print(step.getStepName() + " "); //$NON-NLS-1$
+ }
+ System.out.println("on " + input.getPath()); //$NON-NLS-1$
+ }
+ }
+
+ if (skip) {
+ //This jar was not marked as conditioned, and we are only processing conditioned jars, so do nothing
+ --depth;
+ return input;
+ }
+
+ //pre
+ File workingFile = preProcess(input, workingDir);
+
+ //Extract entries from jar and recurse on them
+ File tempDir = null;
+ if (depth == 0) {
+ tempDir = new File(workingDir, "temp." + workingFile.getName()); //$NON-NLS-1$
+ } else {
+ File parent = workingDir.getParentFile();
+ tempDir = new File(parent, "temp_" + depth + '_' + workingFile.getName()); //$NON-NLS-1$
+ }
+
+ JarFile jar = new JarFile(workingFile, false);
+ Map replacements = new HashMap();
+ Properties inf = Utils.getEclipseInf(workingFile, verbose);
+ extractEntries(jar, tempDir, replacements, inf);
+
+ if (inf != null)
+ adjustInf(workingFile, inf);
+
+ //Recreate the jar with replacements.
+ //TODO: This is not strictly necessary if we didn't change the inf file and didn't change any content
+ File tempJar = null;
+ tempJar = new File(tempDir, workingFile.getName());
+ File parent = tempJar.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
+ recreateJar(jar, jarOut, replacements, tempDir, inf);
+
+ jar.close();
+ if (tempJar != null) {
+ if (!workingFile.equals(input)) {
+ workingFile.delete();
+ }
+ workingFile = tempJar;
+ }
+
+ //post
+ File result = postProcess(workingFile, workingDir);
+
+ //have to normalize after the post steps
+ normalize(result, workingDir);
+
+ if (!result.equals(workingFile) && !workingFile.equals(input))
+ workingFile.delete();
+ if (!result.getParentFile().equals(workingDir)) {
+ File finalFile = new File(workingDir, result.getName());
+ if (finalFile.exists())
+ finalFile.delete();
+ result.renameTo(finalFile);
+ result = finalFile;
+ }
+
+ if (tempDir.exists())
+ Utils.clear(tempDir);
+
+ result.setLastModified(lastModified);
+ --depth;
+ return result;
+ }
+
+ private void normalize(File input, File workingDirectory) {
+ if(input.getName().endsWith(Utils.PACKED_SUFFIX)) {
+ //not a jar
+ return;
+ }
+ try {
+ File tempJar = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
+ JarFile jar = null;
+ try {
+ jar = new JarFile(input, false);
+ } catch (JarException e) {
+ //not a jar
+ return ;
+ }
+ JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
+ InputStream in = null;
+ try {
+ Enumeration entries = jar.entries();
+ for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
+ JarEntry newEntry = new JarEntry(entry.getName());
+ newEntry.setTime(entry.getTime());
+ in = new BufferedInputStream(jar.getInputStream(entry));
+ jarOut.putNextEntry(newEntry);
+ Utils.transferStreams(in, jarOut, false);
+ jarOut.closeEntry();
+ in.close();
+ }
+ } finally {
+ Utils.close(jarOut);
+ Utils.close(jar);
+ Utils.close(in);
+ }
+ tempJar.setLastModified(input.lastModified());
+ input.delete();
+ tempJar.renameTo(input);
+ } catch (IOException e) {
+ if (verbose) {
+ System.out.println("Error normalizing jar " + input.getName()); //$NON-NLS-1$
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessorExecutor.java b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessorExecutor.java
new file mode 100644
index 000000000..92c762562
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.jarprocessor/src/org/eclipse/equinox/p2/jarprocessor/JarProcessorExecutor.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation 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:
+ * IBM - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.p2.jarprocessor;
+
+import java.io.*;
+import java.util.Properties;
+import java.util.zip.ZipException;
+import org.eclipse.equinox.internal.p2.jarprocessor.*;
+import org.eclipse.equinox.internal.p2.jarprocessor.Main.Options;
+
+public class JarProcessorExecutor {
+ public void runJarProcessor(Options options) {
+ if (options.input.isFile() && options.input.getName().endsWith(".zip")) { //$NON-NLS-1$
+ ZipProcessor processor = new ZipProcessor();
+ processor.setWorkingDirectory(options.outputDir);
+ processor.setSignCommand(options.signCommand);
+ processor.setPack(options.pack);
+ processor.setRepack(options.repack || (options.pack && options.signCommand != null));
+ processor.setUnpack(options.unpack);
+ processor.setVerbose(options.verbose);
+ processor.setProcessAll(options.processAll);
+ try {
+ processor.processZip(options.input);
+ } catch (ZipException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ } catch (IOException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ }
+ } else {
+ JarProcessor processor = new JarProcessor();
+ JarProcessor packProcessor = null;
+
+ processor.setWorkingDirectory(options.outputDir);
+ processor.setProcessAll(options.processAll);
+ processor.setVerbose(options.verbose);
+
+ //load options file
+ Properties properties = new Properties();
+ if (options.input.isDirectory()) {
+ File packProperties = new File(options.input, "pack.properties");
+ if (packProperties.exists() && packProperties.isFile()) {
+ InputStream in = null;
+ try {
+ in = new BufferedInputStream(new FileInputStream(packProperties));
+ properties.load(in);
+ } catch (IOException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ } finally {
+ Utils.close(in);
+ }
+ }
+ }
+
+ if (options.unpack)
+ addUnpackStep(processor, properties, options);
+
+ if (options.repack || (options.pack && options.signCommand != null))
+ addPackUnpackStep(processor, properties, options);
+
+ if (options.signCommand != null)
+ addSignStep(processor, properties, options);
+
+ if (options.pack) {
+ packProcessor = new JarProcessor();
+ packProcessor.setWorkingDirectory(options.outputDir);
+ packProcessor.setProcessAll(options.processAll);
+ packProcessor.setVerbose(options.verbose);
+ addPackStep(packProcessor, properties, options);
+ }
+
+ try {
+ process(options.input, options.unpack ? Utils.PACK_GZ_FILTER : Utils.JAR_FILTER, options.verbose, processor, packProcessor);
+ } catch (FileNotFoundException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ }
+ }
+ }
+
+ protected void process(File input, FileFilter filter, boolean verbose, JarProcessor processor, JarProcessor packProcessor) throws FileNotFoundException {
+ if (!input.exists())
+ throw new FileNotFoundException();
+
+ File[] files = null;
+ if (input.isDirectory()) {
+ files = input.listFiles();
+ } else if (filter.accept(input)) {
+ files = new File[] {input};
+ }
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ String dir = processor.getWorkingDirectory();
+ processor.setWorkingDirectory(dir + "/" + files[i].getName()); //$NON-NLS-1$
+ if (packProcessor != null)
+ packProcessor.setWorkingDirectory(dir + "/" + files[i].getName());
+ process(files[i], filter, verbose, processor, packProcessor);
+ processor.setWorkingDirectory(dir);
+ if (packProcessor != null)
+ packProcessor.setWorkingDirectory(dir);
+ } else if (filter.accept(files[i])) {
+ try {
+ File result = processor.processJar(files[i]);
+ if (packProcessor != null && result != null && result.exists()) {
+ packProcessor.processJar(result);
+ }
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void addPackUnpackStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new PackUnpackStep(properties, options.verbose));
+ }
+
+ public void addSignStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new SignCommandStep(properties, options.signCommand, options.verbose));
+ }
+
+ public void addPackStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new PackStep(properties, options.verbose));
+ }
+
+ public void addUnpackStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new UnpackStep(properties, options.verbose));
+ }
+}

Back to the top