You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Jar.java 12 kB

Addition of ZipFileset facilities. Descibed by the author --- With these patches, Zip (and derivative tasks such as Jar and War) can merge the entries of multiple zip files into a single output zip file. The contents of an input zip file may be selectively extracted based on include/exclude patterns. An included zip file is specified using a <fileset> with a "src" attribute, as in: <target name="jartest"> <jar jarfile="utils.jar"> <fileset src="weblogic.jar" includes="weblogic/utils/" excludes="weblogic/utils/jars/,**/reflect/" /> </jar> </target> In this example, a subset of the "weblogic/utils" directory is extracted from weblogic.jar, into utils.jar. The fileset may also contain "prefix" and "fullpath" attributes (the functionality of PrefixedFileSet has been retained in the new class ZipFileSet). Prefixes apply to directory-based and zip-based filesets. The fullpath attributes applies only to a single file in a directory-based fileset. The War task may extract entries from a zip file for all of its filesets (including the files in "classes" and "lib"). The motivation for this change is: 1) There is significant overlap between "jlink" and "zip", and it seemed better to combine them. 2) "jlink" does not support include/exclude patterns which are extremely useful for writing packaging-type tasks such as Zip/Jar/War. This was my main motivation. 3) By adding this functionality to the base task, it can also be used in derivative tasks such as Jar and War. --- Submitted By: Don Ferguson <don@bea.com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268458 13f79535-47bb-0310-9956-ffa450edef68
25 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 1999 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.taskdefs;
  55. import org.apache.tools.ant.BuildException;
  56. import org.apache.tools.ant.FileScanner;
  57. import org.apache.tools.ant.Project;
  58. import org.apache.tools.ant.types.ZipFileSet;
  59. import org.apache.tools.zip.ZipOutputStream;
  60. import java.io.IOException;
  61. import java.io.File;
  62. import java.io.InputStream;
  63. import java.io.FileInputStream;
  64. import java.io.ByteArrayOutputStream;
  65. import java.io.PrintWriter;
  66. import java.io.ByteArrayInputStream;
  67. import java.util.Enumeration;
  68. /**
  69. * Creates a JAR archive.
  70. *
  71. * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a>
  72. */
  73. public class Jar extends Zip {
  74. private File manifestFile;
  75. private Manifest manifest;
  76. private Manifest execManifest;
  77. /** true if a manifest has been specified in the task */
  78. private boolean buildFileManifest = false;
  79. public Jar() {
  80. super();
  81. archiveType = "jar";
  82. emptyBehavior = "create";
  83. setEncoding("UTF8");
  84. }
  85. public void setJarfile(File jarFile) {
  86. log("DEPRECATED - The jarfile attribute is deprecated. Use file attribute instead.");
  87. setFile(jarFile);
  88. }
  89. public void addConfiguredManifest(Manifest newManifest) throws ManifestException {
  90. if (manifest == null) {
  91. manifest = getDefaultManifest();
  92. }
  93. manifest.merge(newManifest);
  94. buildFileManifest = true;
  95. }
  96. public void setManifest(File manifestFile) {
  97. if (!manifestFile.exists()) {
  98. throw new BuildException("Manifest file: " + manifestFile + " does not exist.",
  99. getLocation());
  100. }
  101. this.manifestFile = manifestFile;
  102. InputStream is = null;
  103. try {
  104. is = new FileInputStream(manifestFile);
  105. Manifest newManifest = new Manifest(is);
  106. if (manifest == null) {
  107. manifest = getDefaultManifest();
  108. }
  109. manifest.merge(newManifest);
  110. }
  111. catch (ManifestException e) {
  112. log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  113. throw new BuildException("Invalid Manifest: " + manifestFile, e, getLocation());
  114. }
  115. catch (IOException e) {
  116. throw new BuildException("Unable to read manifest file: " + manifestFile, e);
  117. }
  118. finally {
  119. if (is != null) {
  120. try {
  121. is.close();
  122. }
  123. catch (IOException e) {
  124. // do nothing
  125. }
  126. }
  127. }
  128. }
  129. public void addMetainf(ZipFileSet fs) {
  130. // We just set the prefix for this fileset, and pass it up.
  131. fs.setPrefix("META-INF/");
  132. super.addFileset(fs);
  133. }
  134. protected void initZipOutputStream(ZipOutputStream zOut)
  135. throws IOException, BuildException
  136. {
  137. try {
  138. execManifest = getDefaultManifest();
  139. if (manifest != null) {
  140. execManifest.merge(manifest);
  141. }
  142. for (Enumeration e = execManifest.getWarnings(); e.hasMoreElements(); ) {
  143. log("Manifest warning: " + (String)e.nextElement(), Project.MSG_WARN);
  144. }
  145. zipDir(null, zOut, "META-INF/");
  146. // time to write the manifest
  147. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  148. PrintWriter writer = new PrintWriter(baos);
  149. execManifest.write(writer);
  150. writer.flush();
  151. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  152. super.zipFile(bais, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis());
  153. super.initZipOutputStream(zOut);
  154. }
  155. catch (ManifestException e) {
  156. log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  157. throw new BuildException("Invalid Manifest", e, getLocation());
  158. }
  159. }
  160. private Manifest getDefaultManifest() {
  161. try {
  162. String s = "/org/apache/tools/ant/defaultManifest.mf";
  163. InputStream in = this.getClass().getResourceAsStream(s);
  164. if (in == null) {
  165. throw new BuildException("Could not find default manifest: " + s);
  166. }
  167. return new Manifest(in);
  168. }
  169. catch (ManifestException e) {
  170. throw new BuildException("Default manifest is invalid !!");
  171. }
  172. catch (IOException e) {
  173. throw new BuildException("Unable to read default manifest", e);
  174. }
  175. }
  176. /**
  177. * Handle situation when we encounter a manifest file
  178. *
  179. * If we haven't been given one, we use this one.
  180. *
  181. * If we have, we merge the manifest in, provided it is a new file
  182. * and not the old one from the JAR we are updating
  183. */
  184. private void zipManifestEntry(InputStream is) throws IOException {
  185. try {
  186. if (execManifest == null) {
  187. execManifest = new Manifest(is);
  188. }
  189. else if (isAddingNewFiles()) {
  190. execManifest.merge(new Manifest(is));
  191. }
  192. }
  193. catch (ManifestException e) {
  194. log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  195. throw new BuildException("Invalid Manifest", e, getLocation());
  196. }
  197. }
  198. protected void zipFile(File file, ZipOutputStream zOut, String vPath)
  199. throws IOException
  200. {
  201. // If the file being added is META-INF/MANIFEST.MF, we warn if it's not the
  202. // one specified in the "manifest" attribute - or if it's being added twice,
  203. // meaning the same file is specified by the "manifeset" attribute and in
  204. // a <fileset> element.
  205. if (vPath.equalsIgnoreCase("META-INF/MANIFEST.MF")) {
  206. log("Warning: selected "+archiveType+" files include a META-INF/MANIFEST.MF which will be ignored " +
  207. "(please use manifest attribute to "+archiveType+" task)", Project.MSG_WARN);
  208. } else {
  209. super.zipFile(file, zOut, vPath);
  210. }
  211. }
  212. protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath, long lastModified)
  213. throws IOException
  214. {
  215. // If the file being added is META-INF/MANIFEST.MF, we merge it with the
  216. // current manifest
  217. if (vPath.equalsIgnoreCase("META-INF/MANIFEST.MF")) {
  218. try {
  219. zipManifestEntry(is);
  220. }
  221. catch (IOException e) {
  222. throw new BuildException("Unable to read manifest file: ", e);
  223. }
  224. } else {
  225. super.zipFile(is, zOut, vPath, lastModified);
  226. }
  227. }
  228. /**
  229. * Check whether the archive is up-to-date;
  230. * @param scanners list of prepared scanners containing files to archive
  231. * @param zipFile intended archive file (may or may not exist)
  232. * @return true if nothing need be done (may have done something already); false if
  233. * archive creation should proceed
  234. * @exception BuildException if it likes
  235. */
  236. protected boolean isUpToDate(FileScanner[] scanners, File zipFile) throws BuildException {
  237. // need to handle manifest as a special check
  238. if (buildFileManifest || manifestFile == null) {
  239. java.util.zip.ZipFile theZipFile = null;
  240. try {
  241. theZipFile = new java.util.zip.ZipFile(zipFile);
  242. java.util.zip.ZipEntry entry = theZipFile.getEntry("META-INF/MANIFEST.MF");
  243. if (entry == null) {
  244. log("Updating jar since the current jar has no manifest", Project.MSG_VERBOSE);
  245. return false;
  246. }
  247. Manifest currentManifest = new Manifest(theZipFile.getInputStream(entry));
  248. if (manifest == null) {
  249. manifest = getDefaultManifest();
  250. }
  251. if (!currentManifest.equals(manifest)) {
  252. log("Updating jar since jar manifest has changed", Project.MSG_VERBOSE);
  253. return false;
  254. }
  255. }
  256. catch (Exception e) {
  257. // any problems and we will rebuild
  258. log("Updating jar since cannot read current jar manifest: " + e.getClass().getName() + e.getMessage(),
  259. Project.MSG_VERBOSE);
  260. return false;
  261. }
  262. finally {
  263. if (theZipFile != null) {
  264. try {
  265. theZipFile.close();
  266. }
  267. catch (IOException e) {
  268. //ignore
  269. }
  270. }
  271. }
  272. }
  273. else if (manifestFile.lastModified() > zipFile.lastModified()) {
  274. return false;
  275. }
  276. return super.isUpToDate(scanners, zipFile);
  277. }
  278. protected boolean createEmptyZip(File zipFile) {
  279. // Jar files always contain a manifest and can never be empty
  280. return false;
  281. }
  282. /**
  283. * Make sure we don't think we already have a MANIFEST next time this task
  284. * gets executed.
  285. */
  286. protected void cleanUp() {
  287. super.cleanUp();
  288. }
  289. }