1 | /** | | 1 | /** |
2 | * Create an empty jar file. | | 2 | * Build the zip file. |
3 | * @param zipFile the file to create | | 3 | * This is called twice if doubleFilePass is true. |
4 | * @return true for historic reasons | | 4 | * @throws BuildException on error |
5 | * @throws BuildException on error | | 5 | */ |
6 | */ | | 6 | public void executeMain() throws BuildException { |
7 | protected boolean createEmptyZip(File zipFile) throws BuildException { | | 7 | |
8 | if (!createEmpty) { | | 8 | if (baseDir == null && resources.size() == 0 |
9 | return true; | | 9 | && groupfilesets.size() == 0 && "zip".equals(archiveType)) { |
10 | } | | 10 | throw new BuildException("basedir attribute must be set, " |
11 | | | 11 | + "or at least one " |
12 | if (emptyBehavior.equals("skip")) { | | 12 | + "resource collection must be given!"); |
13 | log("Warning: skipping " + archiveType + " archive " | | 13 | } |
14 | + zipFile + " because no files were included.", | | 14 | |
15 | Project.MSG_WARN); | | 15 | if (zipFile == null) { |
16 | return true; | | 16 | throw new BuildException("You must specify the " |
17 | } else if (emptyBehavior.equals("fail")) { | | 17 | + archiveType + " file to create!"); |
18 | throw new BuildException("Cannot create " + archiveType | | 18 | } |
19 | + " archive " + zipFile | | 19 | |
20 | + ": no files were included.", | | 20 | if (zipFile.exists() && !zipFile.isFile()) { |
21 | getLocation()); | | 21 | throw new BuildException(zipFile + " is not a file."); |
22 | } | | 22 | } |
23 | | | 23 | |
24 | ZipOutputStream zOut = null; | | 24 | if (zipFile.exists() && !zipFile.canWrite()) { |
25 | try { | | 25 | throw new BuildException(zipFile + " is read-only."); |
26 | log("Building MANIFEST-only jar: " | | 26 | } |
27 | + getDestFile().getAbsolutePath()); | | 27 | |
28 | zOut = new ZipOutputStream(new FileOutputStream(getDestFile())); | | 28 | // Renamed version of original file, if it exists |
29 | | | 29 | File renamedFile = null; |
30 | zOut.setEncoding(getEncoding()); | | 30 | addingNewFiles = true; |
31 | if (isCompress()) { | | 31 | |
32 | zOut.setMethod(ZipOutputStream.DEFLATED); | | 32 | // Whether or not an actual update is required - |
33 | } else { | | 33 | // we don't need to update if the original file doesn't exist |
34 | zOut.setMethod(ZipOutputStream.STORED); | | 34 | if (doUpdate && !zipFile.exists()) { |
35 | } | | 35 | doUpdate = false; |
36 | initZipOutputStream(zOut); | | 36 | log("ignoring update attribute as " + archiveType |
37 | finalizeZipOutputStream(zOut); | | 37 | + " doesn't exist.", Project.MSG_DEBUG); |
38 | } catch (IOException ioe) { | | 38 | } |
39 | throw new BuildException("Could not create almost empty JAR archive" | | 39 | |
40 | + " (" + ioe.getMessage() + ")", ioe, | | 40 | // Add the files found in groupfileset to fileset |
41 | getLocation()); | | 41 | for (int i = 0; i < groupfilesets.size(); i++) { |
42 | } finally { | | 42 | |
43 | // Close the output stream. | | 43 | log("Processing groupfileset ", Project.MSG_VERBOSE); |
44 | try { | | 44 | FileSet fs = (FileSet) groupfilesets.elementAt(i); |
45 | if (zOut != null) { | | 45 | FileScanner scanner = fs.getDirectoryScanner(getProject()); |
46 | zOut.close(); | | 46 | String[] files = scanner.getIncludedFiles(); |
47 | } | | 47 | File basedir = scanner.getBasedir(); |
48 | } catch (IOException ex) { | | 48 | for (int j = 0; j < files.length; j++) { |
49 | // Ignore close exception | | 49 | |
50 | } | | 50 | log("Adding file " + files[j] + " to fileset", |
51 | createEmpty = false; | | 51 | Project.MSG_VERBOSE); |
52 | } | | 52 | ZipFileSet zf = new ZipFileSet(); |
53 | return true; | | 53 | zf.setProject(getProject()); |
54 | } | | 54 | zf.setSrc(new File(basedir, files[j])); |
| | | 55 | add(zf); |
| | | 56 | filesetsFromGroupfilesets.addElement(zf); |
| | | 57 | } |
| | | 58 | } |
| | | 59 | |
| | | 60 | // collect filesets to pass them to getResourcesToAdd |
| | | 61 | Vector vfss = new Vector(); |
| | | 62 | if (baseDir != null) { |
| | | 63 | FileSet fs = (FileSet) getImplicitFileSet().clone(); |
| | | 64 | fs.setDir(baseDir); |
| | | 65 | vfss.addElement(fs); |
| | | 66 | } |
| | | 67 | for (int i = 0; i < resources.size(); i++) { |
| | | 68 | ResourceCollection rc = (ResourceCollection) resources.elementAt(i); |
| | | 69 | vfss.addElement(rc); |
| | | 70 | } |
| | | 71 | |
| | | 72 | ResourceCollection[] fss = new ResourceCollection[vfss.size()]; |
| | | 73 | vfss.copyInto(fss); |
| | | 74 | boolean success = false; |
| | | 75 | try { |
| | | 76 | // can also handle empty archives |
| | | 77 | ArchiveState state = getResourcesToAdd(fss, zipFile, false); |
| | | 78 | |
| | | 79 | // quick exit if the target is up to date |
| | | 80 | if (!state.isOutOfDate()) { |
| | | 81 | return; |
| | | 82 | } |
| | | 83 | |
| | | 84 | if (!zipFile.exists() && state.isWithoutAnyResources()) { |
| | | 85 | createEmptyZip(zipFile); |
| | | 86 | return; |
| | | 87 | } |
| | | 88 | Resource[][] addThem = state.getResourcesToAdd(); |
| | | 89 | |
| | | 90 | if (doUpdate) { |
| | | 91 | renamedFile = |
| | | 92 | FILE_UTILS.createTempFile("zip", ".tmp", |
| | | 93 | zipFile.getParentFile()); |
| | | 94 | renamedFile.deleteOnExit(); |
| | | 95 | |
| | | 96 | try { |
| | | 97 | FILE_UTILS.rename(zipFile, renamedFile); |
| | | 98 | } catch (SecurityException e) { |
| | | 99 | throw new BuildException( |
| | | 100 | "Not allowed to rename old file (" |
| | | 101 | + zipFile.getAbsolutePath() |
| | | 102 | + ") to temporary file"); |
| | | 103 | } catch (IOException e) { |
| | | 104 | throw new BuildException( |
| | | 105 | "Unable to rename old file (" |
| | | 106 | + zipFile.getAbsolutePath() |
| | | 107 | + ") to temporary file"); |
| | | 108 | } |
| | | 109 | } |
| | | 110 | |
| | | 111 | String action = doUpdate ? "Updating " : "Building "; |
| | | 112 | |
| | | 113 | log(action + archiveType + ": " + zipFile.getAbsolutePath()); |
| | | 114 | |
| | | 115 | ZipOutputStream zOut = null; |
| | | 116 | try { |
| | | 117 | if (!skipWriting) { |
| | | 118 | zOut = new ZipOutputStream(zipFile); |
| | | 119 | |
| | | 120 | zOut.setEncoding(encoding); |
| | | 121 | zOut.setMethod(doCompress |
| | | 122 | ? ZipOutputStream.DEFLATED : ZipOutputStream.STORED); |
| | | 123 | zOut.setLevel(level); |
| | | 124 | } |
| | | 125 | initZipOutputStream(zOut); |
| | | 126 | |
| | | 127 | // Add the explicit resource collections to the archive. |
| | | 128 | for (int i = 0; i < fss.length; i++) { |
| | | 129 | if (addThem[i].length != 0) { |
| | | 130 | addResources(fss[i], addThem[i], zOut); |
| | | 131 | } |
| | | 132 | } |
| | | 133 | |
| | | 134 | if (doUpdate) { |
| | | 135 | addingNewFiles = false; |
| | | 136 | ZipFileSet oldFiles = new ZipFileSet(); |
| | | 137 | oldFiles.setProject(getProject()); |
| | | 138 | oldFiles.setSrc(renamedFile); |
| | | 139 | oldFiles.setDefaultexcludes(false); |
| | | 140 | |
| | | 141 | for (int i = 0; i < addedFiles.size(); i++) { |
| | | 142 | PatternSet.NameEntry ne = oldFiles.createExclude(); |
| | | 143 | ne.setName((String) addedFiles.elementAt(i)); |
| | | 144 | } |
| | | 145 | DirectoryScanner ds = |
| | | 146 | oldFiles.getDirectoryScanner(getProject()); |
| | | 147 | ((ZipScanner) ds).setEncoding(encoding); |
| | | 148 | |
| | | 149 | String[] f = ds.getIncludedFiles(); |
| | | 150 | Resource[] r = new Resource[f.length]; |
| | | 151 | for (int i = 0; i < f.length; i++) { |
| | | 152 | r[i] = ds.getResource(f[i]); |
| | | 153 | } |
| | | 154 | |
| | | 155 | if (!doFilesonly) { |
| | | 156 | String[] d = ds.getIncludedDirectories(); |
| | | 157 | Resource[] dr = new Resource[d.length]; |
| | | 158 | for (int i = 0; i < d.length; i++) { |
| | | 159 | dr[i] = ds.getResource(d[i]); |
| | | 160 | } |
| | | 161 | Resource[] tmp = r; |
| | | 162 | r = new Resource[tmp.length + dr.length]; |
| | | 163 | System.arraycopy(dr, 0, r, 0, dr.length); |
| | | 164 | System.arraycopy(tmp, 0, r, dr.length, tmp.length); |
| | | 165 | } |
| | | 166 | addResources(oldFiles, r, zOut); |
| | | 167 | } |
| | | 168 | if (zOut != null) { |
| | | 169 | zOut.setComment(comment); |
| | | 170 | } |
| | | 171 | finalizeZipOutputStream(zOut); |
| | | 172 | |
| | | 173 | // If we've been successful on an update, delete the |
| | | 174 | // temporary file |
| | | 175 | if (doUpdate) { |
| | | 176 | if (!renamedFile.delete()) { |
| | | 177 | log ("Warning: unable to delete temporary file " |
| | | 178 | + renamedFile.getName(), Project.MSG_WARN); |
| | | 179 | } |
| | | 180 | } |
| | | 181 | success = true; |
| | | 182 | } finally { |
| | | 183 | // Close the output stream. |
| | | 184 | try { |
| | | 185 | if (zOut != null) { |
| | | 186 | zOut.close(); |
| | | 187 | } |
| | | 188 | } catch (IOException ex) { |
| | | 189 | // If we're in this finally clause because of an |
| | | 190 | // exception, we don't really care if there's an |
| | | 191 | // exception when closing the stream. E.g. if it |
| | | 192 | // throws "ZIP file must have at least one entry", |
| | | 193 | // because an exception happened before we added |
| | | 194 | // any files, then we must swallow this |
| | | 195 | // exception. Otherwise, the error that's reported |
| | | 196 | // will be the close() error, which is not the |
| | | 197 | // real cause of the problem. |
| | | 198 | if (success) { |
| | | 199 | throw ex; |
| | | 200 | } |
| | | 201 | } |
| | | 202 | } |
| | | 203 | } catch (IOException ioe) { |
| | | 204 | String msg = "Problem creating " + archiveType + ": " |
| | | 205 | + ioe.getMessage(); |
| | | 206 | |
| | | 207 | // delete a bogus ZIP file (but only if it's not the original one) |
| | | 208 | if ((!doUpdate || renamedFile != null) && !zipFile.delete()) { |
| | | 209 | msg += " (and the archive is probably corrupt but I could not " |
| | | 210 | + "delete it)"; |
| | | 211 | } |
| | | 212 | |
| | | 213 | if (doUpdate && renamedFile != null) { |
| | | 214 | try { |
| | | 215 | FILE_UTILS.rename(renamedFile, zipFile); |
| | | 216 | } catch (IOException e) { |
| | | 217 | msg += " (and I couldn't rename the temporary file " |
| | | 218 | + renamedFile.getName() + " back)"; |
| | | 219 | } |
| | | 220 | } |
| | | 221 | |
| | | 222 | throw new BuildException(msg, ioe, getLocation()); |
| | | 223 | } finally { |
| | | 224 | cleanUp(); |
| | | 225 | } |
| | | 226 | } |