/******************************************************************************* * 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.update.internal.jarprocessor; import java.io.*; import java.util.*; import java.util.jar.*; 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(); } }