/******************************************************************* * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein * are the sole and exclusive property of Cloudsmith Inc. and may * not be disclosed, used, modified, copied or distributed without * prior written consent or license from Cloudsmith Inc. ******************************************************************/ package org.eclipse.buckminster.jarprocessor; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.jar.JarInputStream; import java.util.regex.Matcher; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.eclipse.buckminster.core.helpers.BMProperties; import org.eclipse.buckminster.core.helpers.TextUtils; class JarInfo implements IConstants { static final String PROP_PACK200_CONDITIONED = "pack200.conditioned"; //$NON-NLS-1$ static final String PROP_PACK200_ARGS = "pack200.args"; //$NON-NLS-1$ static final String PROP_PACK200_DEFAULT_ARGS = "pack200.default.args"; //$NON-NLS-1$ static final String PROP_IS_EXCLUDE = "jarprocessor.exclude"; //$NON-NLS-1$ static final String PROP_IS_EXCLUDE_PACK = "jarprocessor.exclude.pack"; //$NON-NLS-1$ static final String PROP_IS_EXCLUDE_SIGN = "jarprocessor.exclude.sign"; //$NON-NLS-1$ static final String PROP_IS_EXCLUDE_CHILDREN = "jarprocessor.exclude.children"; //$NON-NLS-1$ static final String PROP_BUCK_IS_EXCLUDE_CHILDREN = "buckminster.exclude.children"; //$NON-NLS-1$ static final String PROP_IS_EXCLUDE_CHILDREN_PACK = "jarprocessor.exclude.children.pack"; //$NON-NLS-1$ static final String PROP_IS_EXCLUDE_CHILDREN_SIGN = "jarprocessor.exclude.children.sign"; //$NON-NLS-1$ static JarInfo getJarInfo(JarInfo parent, String jarName, ZipInputStream input) throws IOException { JarInfo jarInfo = new JarInfo(parent, jarName); ZipEntry entry; HashSet<String> alreadyPacked = new HashSet<String>(); while ((entry = input.getNextEntry()) != null) { String name = entry.getName(); if (name.endsWith(JAR_SUFFIX)) { if (alreadyPacked.contains(name)) continue; JarInfo nested = getJarInfo(jarInfo, name, new JarInputStream(input)); if (nested.isSigned() && !nested.isConditioned()) continue; if (!(nested.hasClasses() || nested.isNested())) continue; if (jarInfo.nestedInfos == null) jarInfo.nestedInfos = new HashMap<String, JarInfo>(); jarInfo.nestedInfos.put(name, nested); continue; } if (!jarInfo.classes && name.endsWith(CLASS_SUFFIX)) { jarInfo.classes = true; continue; } if (name.endsWith(PACK_SUFFIX)) { alreadyPacked.add(name.substring(0, name.length() - PACK_SUFFIX.length())); continue; } if (name.endsWith(PACK_GZ_SUFFIX)) { alreadyPacked.add(name.substring(0, name.length() - PACK_GZ_SUFFIX.length())); continue; } if (!name.startsWith(META_INF)) continue; name = name.substring(META_INF.length()); if (name.indexOf('/') > 0) continue; if (jarInfo.eclipseInf == null && name.equals(ECLIPSE_INF)) { jarInfo.eclipseInf = new BMProperties(input); continue; } if (name.endsWith(SIGNATURE_SUFFIX)) jarInfo.signed = true; } if (jarInfo.eclipseInf == null) jarInfo.eclipseInf = Collections.emptyMap(); if (jarInfo.nestedInfos == null || jarInfo.isExcludeChildren()) jarInfo.nestedInfos = Collections.emptyMap(); else { // Remove info for all nested jars that are already packed. Such // infos // will only be present in jars where both the canonical and packed // form // has been retained. // for (String name : alreadyPacked) jarInfo.nestedInfos.remove(name); } return jarInfo; } private boolean signed = false; private boolean classes = false; private final String jarName; private final JarInfo parent; private Map<String, JarInfo> nestedInfos = null; private Map<String, String> eclipseInf = null; private JarInfo(JarInfo parentInfo, String jname) { parent = parentInfo; jarName = jname; } @Override public String toString() { StringBuilder bld = new StringBuilder(); toString(bld); return bld.toString(); } void appendArgs(List<String> args) { appendArgs(args, true); } Map<String, String> getEclipseInf() { Map<String, String> map = new HashMap<String, String>(); if (eclipseInf != null) map.putAll(eclipseInf); List<String> args = new ArrayList<String>(); appendArgs(args); if (!args.isEmpty()) map.put(PROP_PACK200_ARGS, TextUtils.concat(args, " ")); //$NON-NLS-1$ return map; } JarInfo getNestedInfo(String name) { return nestedInfos.get(name); } boolean hasClasses() { return classes; } boolean hasEclipseInf() { return eclipseInf != null && !eclipseInf.isEmpty(); } boolean isConditioned() { return "true".equalsIgnoreCase(eclipseInf.get(PROP_PACK200_CONDITIONED)); //$NON-NLS-1$ } boolean isExclude() { return "true".equalsIgnoreCase(eclipseInf.get(PROP_IS_EXCLUDE)); //$NON-NLS-1$ } boolean isExcludeChildren() { String prop = eclipseInf.get(PROP_BUCK_IS_EXCLUDE_CHILDREN); if (prop == null) prop = eclipseInf.get(PROP_IS_EXCLUDE_CHILDREN); return "true".equalsIgnoreCase(prop); //$NON-NLS-1$ } boolean isExcludeChildrenPack() { return isExcludeChildren() || "true".equalsIgnoreCase(eclipseInf.get(PROP_IS_EXCLUDE_CHILDREN_PACK)); //$NON-NLS-1$ } boolean isExcludeChildrenSign() { return isExcludeChildren() || "true".equalsIgnoreCase(eclipseInf.get(PROP_IS_EXCLUDE_CHILDREN_SIGN)); //$NON-NLS-1$ } boolean isExcludePack() { return isExclude() || "true".equalsIgnoreCase(eclipseInf.get(PROP_IS_EXCLUDE_PACK)); //$NON-NLS-1$ } boolean isExcludeSign() { return isExclude() || "true".equalsIgnoreCase(eclipseInf.get(PROP_IS_EXCLUDE_SIGN)); //$NON-NLS-1$ } boolean isNested() { return !nestedInfos.isEmpty(); } boolean isSigned() { return signed; } void toString(StringBuilder bld) { if (parent != null) { parent.toString(bld); bld.append("!/"); //$NON-NLS-1$ } bld.append(jarName); } private void appendArgs(List<String> args, boolean atLeaf) { if (parent != null) { parent.appendArgs(args, false); if (parent.isExcludeChildren()) return; } boolean hasEffort = false; if (atLeaf && !hasClasses()) { // This is the only reasonable effort for a jar that contains no // classes. args.add("-E0"); //$NON-NLS-1$ hasEffort = true; } if (eclipseInf != null) { for (String arg : TextUtils.splitAndTrim(eclipseInf.get(PROP_PACK200_ARGS), " \t\n")) //$NON-NLS-1$ { Matcher m = RecursivePack200.EFFORT_PATTERN.matcher(arg); if (m.matches()) { if (hasEffort || !atLeaf) continue; hasEffort = true; } args.add(arg); } } if (!hasEffort && atLeaf) args.add("-E4"); //$NON-NLS-1$ } }