| /******************************************************************************* |
| * Copyright (c) 2012, 2015 Sonatype Inc. 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: |
| * Sonatype Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.tycho.extras.pack200; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.Enumeration; |
| import java.util.List; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| import java.util.jar.JarOutputStream; |
| |
| import org.apache.maven.artifact.Artifact; |
| import org.codehaus.plexus.component.annotations.Component; |
| import org.codehaus.plexus.component.annotations.Requirement; |
| import org.codehaus.plexus.logging.Logger; |
| |
| @Component(role = Pack200Archiver.class) |
| public class Pack200Archiver { |
| |
| @Requirement |
| private Logger log; |
| |
| private Pack200Wrapper packWrapper = new Pack200Wrapper(); |
| private ForkedPack200Wrapper forkedPackWrapper = new ForkedPack200Wrapper(); |
| |
| /** |
| * @param file |
| * source jar file |
| * @param packFile |
| * target pack file |
| * @return <code>true</code> if the target pack file was created, <code>false</code> if the |
| * target file was not created |
| */ |
| public boolean normalize(List<Artifact> pluginArtifacts, File file, File packFile, boolean fork) throws IOException { |
| File jarToBePacked = file; |
| boolean shouldNormalize = false; |
| boolean jarToBePackedIsTempFile = false; |
| try (JarFile jarFile = new JarFile(file)) { |
| EclipseInf eclipseInf = EclipseInf.readEclipseInf(jarFile); |
| assertSupportedEclipseInf(eclipseInf); |
| if (eclipseInf == null || (eclipseInf.shouldPack() && !eclipseInf.isPackNormalized())) { |
| if (isSigned(jarFile)) { |
| throw new IOException("pack200:normalize cannot be called for signed jar " + file); |
| } |
| shouldNormalize = true; |
| if (eclipseInf != null) { |
| eclipseInf.setPackNormalized(); |
| jarToBePacked = File.createTempFile(file.getName(), ".prepack"); |
| jarToBePackedIsTempFile = true; |
| updateEclipseInf(jarFile, eclipseInf, jarToBePacked); |
| } |
| |
| } |
| } |
| if (shouldNormalize) { |
| try { |
| log.info("Pack200 normalizing jar " + file.getAbsolutePath()); |
| getPackWrapper(fork).pack(pluginArtifacts, jarToBePacked, packFile); |
| } finally { |
| if (jarToBePackedIsTempFile) { |
| if (!jarToBePacked.delete()) { |
| throw new IOException("Could not delete temporary file " + jarToBePacked.getAbsolutePath()); |
| } |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| private Pack200Wrapper getPackWrapper(boolean fork) { |
| return fork ? forkedPackWrapper : packWrapper; |
| } |
| |
| protected void assertSupportedEclipseInf(EclipseInf eclipseInf) throws IOException { |
| if (eclipseInf != null && eclipseInf.shouldPack() && eclipseInf.shouldSign()) { |
| throw new IOException("Pack200 and jar signing cannot be both enabled in " + EclipseInf.PATH_ECLIPSEINF |
| + ". See bug 388629."); |
| } |
| } |
| |
| private void updateEclipseInf(JarFile jarFile, EclipseInf eclipseInf, File tmpFile) throws IOException { |
| try (JarOutputStream jos = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tmpFile)))) { |
| Enumeration<JarEntry> entries = jarFile.entries(); |
| while (entries.hasMoreElements()) { |
| JarEntry entry = entries.nextElement(); |
| if (!entry.getName().equals(EclipseInf.PATH_ECLIPSEINF)) { |
| copyJarEntry(jarFile, entry, jos); |
| } |
| } |
| JarEntry entry = new JarEntry(EclipseInf.PATH_ECLIPSEINF); |
| jos.putNextEntry(entry); |
| jos.write(eclipseInf.toByteArray()); |
| jos.closeEntry(); |
| } |
| } |
| |
| private boolean isSigned(JarFile jarFile) throws IOException { |
| Enumeration<JarEntry> entries = jarFile.entries(); |
| while (entries.hasMoreElements()) { |
| JarEntry entry = entries.nextElement(); |
| String name = entry.getName(); |
| if (name.startsWith("META-INF/") && name.endsWith(".SF")) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private void copyJarEntry(JarFile jarFile, JarEntry entry, JarOutputStream jos) throws IOException { |
| jos.putNextEntry(entry); |
| |
| InputStream is = jarFile.getInputStream(entry); |
| byte[] buf = new byte[4096]; |
| int n; |
| while ((n = is.read(buf)) != -1) { |
| jos.write(buf, 0, n); |
| } |
| |
| jos.closeEntry(); |
| } |
| |
| public void unpack(List<Artifact> pluginArtifacts, File packFile, File jarFile, boolean fork) throws IOException { |
| getPackWrapper(fork).unpack(pluginArtifacts, packFile, jarFile); |
| } |
| |
| public boolean pack(List<Artifact> pluginArtifacts, File file, File packFile, boolean fork) throws IOException { |
| EclipseInf eclipseInf = null; |
| try (JarFile jarFile = new JarFile(file)) { |
| eclipseInf = EclipseInf.readEclipseInf(jarFile); |
| } |
| assertSupportedEclipseInf(eclipseInf); |
| if (eclipseInf == null || (eclipseInf.shouldPack() && eclipseInf.isPackNormalized())) { |
| log.info("Pack200 packing jar " + file.getAbsolutePath()); |
| getPackWrapper(fork).pack(pluginArtifacts, file, packFile); |
| return true; |
| } |
| return false; |
| } |
| |
| } |