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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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.*;
  56. import org.apache.tools.ant.types.ZipFileSet;
  57. import org.apache.tools.zip.*;
  58. import java.io.*;
  59. import java.util.Enumeration;
  60. /**
  61. * Creates a JAR archive.
  62. *
  63. * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a>
  64. */
  65. public class Jar extends Zip {
  66. private File manifestFile;
  67. private Manifest manifest;
  68. private Manifest execManifest;
  69. private boolean buildFileManifest = false;
  70. public Jar() {
  71. super();
  72. archiveType = "jar";
  73. emptyBehavior = "create";
  74. setEncoding("UTF8");
  75. }
  76. public void setJarfile(File jarFile) {
  77. super.setZipfile(jarFile);
  78. }
  79. public void addConfiguredManifest(Manifest newManifest) throws ManifestException {
  80. if (manifest == null) {
  81. manifest = getDefaultManifest();
  82. }
  83. manifest.merge(newManifest);
  84. buildFileManifest = true;
  85. }
  86. public void setManifest(File manifestFile) {
  87. if (!manifestFile.exists()) {
  88. throw new BuildException("Manifest file: " + manifestFile + " does not exist.",
  89. getLocation());
  90. }
  91. this.manifestFile = manifestFile;
  92. InputStream is = null;
  93. try {
  94. is = new FileInputStream(manifestFile);
  95. Manifest newManifest = new Manifest(is);
  96. if (manifest == null) {
  97. manifest = getDefaultManifest();
  98. }
  99. manifest.merge(newManifest);
  100. }
  101. catch (ManifestException e) {
  102. log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  103. throw new BuildException("Invalid Manifest: " + manifestFile, e, getLocation());
  104. }
  105. catch (IOException e) {
  106. throw new BuildException("Unable to read manifest file: " + manifestFile, e);
  107. }
  108. finally {
  109. if (is != null) {
  110. try {
  111. is.close();
  112. }
  113. catch (IOException e) {
  114. // do nothing
  115. }
  116. }
  117. }
  118. }
  119. public void addMetainf(ZipFileSet fs) {
  120. // We just set the prefix for this fileset, and pass it up.
  121. fs.setPrefix("META-INF/");
  122. super.addFileset(fs);
  123. }
  124. protected void initZipOutputStream(ZipOutputStream zOut)
  125. throws IOException, BuildException
  126. {
  127. try {
  128. // If no manifest is specified, add the default one.
  129. if (manifest == null) {
  130. execManifest = null;
  131. }
  132. else {
  133. execManifest = new Manifest();
  134. execManifest.merge(manifest);
  135. }
  136. zipDir(null, zOut, "META-INF/");
  137. super.initZipOutputStream(zOut);
  138. }
  139. catch (ManifestException e) {
  140. log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  141. throw new BuildException("Invalid Manifest", e, getLocation());
  142. }
  143. }
  144. private Manifest getDefaultManifest() {
  145. try {
  146. String s = "/org/apache/tools/ant/defaultManifest.mf";
  147. InputStream in = this.getClass().getResourceAsStream(s);
  148. if (in == null) {
  149. throw new BuildException("Could not find default manifest: " + s);
  150. }
  151. return new Manifest(in);
  152. }
  153. catch (ManifestException e) {
  154. throw new BuildException("Default manifest is invalid !!");
  155. }
  156. catch (IOException e) {
  157. throw new BuildException("Unable to read default manifest", e);
  158. }
  159. }
  160. protected void finalizeZipOutputStream(ZipOutputStream zOut)
  161. throws IOException, BuildException {
  162. if (execManifest == null) {
  163. execManifest = getDefaultManifest();
  164. }
  165. for (Enumeration e = execManifest.getWarnings(); e.hasMoreElements(); ) {
  166. log("Manifest warning: " + (String)e.nextElement(), Project.MSG_WARN);
  167. }
  168. // time to write the manifest
  169. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  170. PrintWriter writer = new PrintWriter(baos);
  171. execManifest.write(writer);
  172. writer.flush();
  173. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  174. super.zipFile(bais, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis());
  175. super.finalizeZipOutputStream(zOut);
  176. }
  177. /**
  178. * Handle situation when we encounter a manifest file
  179. *
  180. * If we haven't been given one, we use this one.
  181. *
  182. * If we have, we merge the manifest in, provided it is a new file
  183. * and not the old one from the JAR we are updating
  184. */
  185. private void zipManifestEntry(InputStream is) throws IOException {
  186. try {
  187. if (execManifest == null) {
  188. execManifest = new Manifest(is);
  189. }
  190. else if (isAddingNewFiles()) {
  191. execManifest.merge(new Manifest(is));
  192. }
  193. }
  194. catch (ManifestException e) {
  195. log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  196. throw new BuildException("Invalid Manifest", e, getLocation());
  197. }
  198. }
  199. protected void zipFile(File file, ZipOutputStream zOut, String vPath)
  200. throws IOException
  201. {
  202. // If the file being added is META-INF/MANIFEST.MF, we merge it with the
  203. // current manifest
  204. if (vPath.equalsIgnoreCase("META-INF/MANIFEST.MF")) {
  205. InputStream is = null;
  206. try {
  207. is = new FileInputStream(file);
  208. zipManifestEntry(is);
  209. }
  210. catch (IOException e) {
  211. throw new BuildException("Unable to read manifest file: " + file, e);
  212. }
  213. finally {
  214. if (is != null) {
  215. try {
  216. is.close();
  217. }
  218. catch (IOException e) {
  219. // do nothing
  220. }
  221. }
  222. }
  223. } else {
  224. super.zipFile(file, zOut, vPath);
  225. }
  226. }
  227. protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath, long lastModified)
  228. throws IOException
  229. {
  230. // If the file being added is META-INF/MANIFEST.MF, we merge it with the
  231. // current manifest
  232. if (vPath.equalsIgnoreCase("META-INF/MANIFEST.MF")) {
  233. try {
  234. zipManifestEntry(is);
  235. }
  236. catch (IOException e) {
  237. throw new BuildException("Unable to read manifest file: ", e);
  238. }
  239. } else {
  240. super.zipFile(is, zOut, vPath, lastModified);
  241. }
  242. }
  243. /**
  244. * Check whether the archive is up-to-date;
  245. * @param scanners list of prepared scanners containing files to archive
  246. * @param zipFile intended archive file (may or may not exist)
  247. * @return true if nothing need be done (may have done something already); false if
  248. * archive creation should proceed
  249. * @exception BuildException if it likes
  250. */
  251. protected boolean isUpToDate(FileScanner[] scanners, File zipFile) throws BuildException {
  252. // need to handle manifest as a special check
  253. if (buildFileManifest || manifestFile == null) {
  254. java.util.zip.ZipFile theZipFile = null;
  255. try {
  256. theZipFile = new java.util.zip.ZipFile(zipFile);
  257. java.util.zip.ZipEntry entry = theZipFile.getEntry("META-INF/MANIFEST.MF");
  258. if (entry == null) {
  259. return false;
  260. }
  261. Manifest currentManifest = new Manifest(theZipFile.getInputStream(entry));
  262. if (!currentManifest.equals(manifest)) {
  263. return false;
  264. }
  265. }
  266. catch (Exception e) {
  267. // any problems and we will rebuild
  268. return false;
  269. }
  270. finally {
  271. if (theZipFile != null) {
  272. try {
  273. theZipFile.close();
  274. }
  275. catch (IOException e) {
  276. //ignore
  277. }
  278. }
  279. }
  280. }
  281. else if (manifestFile.lastModified() > zipFile.lastModified()) {
  282. return false;
  283. }
  284. return super.isUpToDate(scanners, zipFile);
  285. }
  286. protected boolean createEmptyZip(File zipFile) {
  287. // Jar files always contain a manifest and can never be empty
  288. return false;
  289. }
  290. /**
  291. * Make sure we don't think we already have a MANIFEST next time this task
  292. * gets executed.
  293. */
  294. protected void cleanUp() {
  295. super.cleanUp();
  296. }
  297. }