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

FileUtil.java 29KB

21 jaren geleden
18 jaren geleden
21 jaren geleden
18 jaren geleden
21 jaren geleden
21 jaren geleden
21 jaren geleden
5 jaren geleden
21 jaren geleden
5 jaren geleden
21 jaren geleden
21 jaren geleden
20 jaren geleden
21 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2000 Xerox Corporation.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Xerox/PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.testing.util;
  13. import java.io.File;
  14. import java.io.FileFilter;
  15. import java.io.FileInputStream;
  16. import java.io.FileOutputStream;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.OutputStream;
  20. import java.io.PrintWriter;
  21. import java.io.StringBufferInputStream;
  22. import java.io.StringWriter;
  23. import java.net.MalformedURLException;
  24. import java.net.URL;
  25. import java.util.ArrayList;
  26. import java.util.Arrays;
  27. import java.util.Collection;
  28. import java.util.Enumeration;
  29. import java.util.Iterator;
  30. import java.util.Vector;
  31. import java.util.jar.Attributes;
  32. import java.util.jar.JarOutputStream;
  33. import java.util.jar.Manifest;
  34. import java.util.zip.ZipEntry;
  35. import java.util.zip.ZipFile;
  36. import java.util.zip.ZipOutputStream;
  37. /**
  38. * misc file utilities
  39. */
  40. public class FileUtil {
  41. /** default filename if URL has none (i.e., a directory URL): index.html */
  42. public static final String DEFAULT_URL_FILENAME = "index.html";
  43. /**
  44. * @param args the String[]
  45. * <code>{ "-copy", "-srcFile" | "-srcUrl", {src}, "-destFile", {destFile} }</code>
  46. */
  47. public static void main (String[] args) {
  48. if (null == args) return;
  49. for (int i = 0; (i+4) < args.length; i++) {
  50. if ("-copy".equals(args[i])) {
  51. String arg = args[++i];
  52. String src = null;
  53. String destFile = null;
  54. boolean srcIsFile = ("-srcFile".equals(arg));
  55. if (srcIsFile) {
  56. src = args[++i];
  57. } else if ("-srcUrl".equals(arg)) {
  58. src = args[++i];
  59. }
  60. if ((null != src) && ("-destFile".equals(args[++i]))) {
  61. destFile = args[++i];
  62. StringBuffer errs = new StringBuffer();
  63. if (srcIsFile) {
  64. copyFile(new File(src), new File(destFile), errs);
  65. } else {
  66. URL url = null;
  67. try { url = new URL(src) ; }
  68. catch (MalformedURLException e) { render(e, errs); }
  69. if (null != url) {
  70. copyURL(url, new File(destFile), errs);
  71. }
  72. }
  73. if (0 < errs.length()) {
  74. System.err.println("Error copying " + src + " to " + destFile);
  75. System.err.println(errs.toString());
  76. }
  77. }
  78. } // ("-copy".equals(args[i])){
  79. }
  80. } // end of main ()
  81. /**
  82. * Generate a list of missing and extra files by comparison to a
  83. * timestamp, optionally excluding certain files.
  84. * This is a call to select all files after a given time:
  85. *
  86. * <pre>Diffs d = dirDiffs(dir, givenTime, null, null, null);</pre>
  87. *
  88. * Given files
  89. * <pre>classes/Foo.class
  90. * classes/bar/Bash.class
  91. * classes/Old.class
  92. * classes/one/Unexpected.class
  93. * classes/start.gif</pre>
  94. * where only Old.class predated startTime, this is a call that
  95. * reports "one/Unexpected.class" as unexpected and "Foo"
  96. * as missing:
  97. * <pre>String requireSuffix = ".class";
  98. * String[] expectedPaths = new String[] { "Foo", "bar/Bas" };
  99. * File file = new File("classes");
  100. * Diffs d = dirDiffs(dir, startTime, requireSuffix,expectedPaths, true);</pre>
  101. *
  102. * @param label the String to use for the Diffs label
  103. * @param dir the File for the dir to search
  104. * @param startTime collect files modified after this time
  105. * (ignored if less than 0)
  106. * @param requireSuffix ignore all actual files without this suffix
  107. * (ignored if null)
  108. * @param expectedPaths paths (relative to dir) of the expected files
  109. * (if null, none expected)
  110. * @param acceptFilePrefix if true, then accept a file which
  111. * differs from an expected file name only by a suffix
  112. * (which need not begin with ".").
  113. */
  114. public static Diffs dirDiffs( // XXX too complicated, weak prefix checking
  115. final String label,
  116. final File dir,
  117. final long startTime,
  118. final String requiredSuffix,
  119. final String[] expectedPaths,
  120. final boolean acceptFilePrefix) {
  121. LangUtil.throwIaxIfNull(dir, "dir");
  122. final boolean checkExpected = !LangUtil.isEmpty(expectedPaths);
  123. // normalize sources to ignore
  124. final ArrayList expected = (!checkExpected ? null : new ArrayList());
  125. if (checkExpected) {
  126. for (int i = 0; i < expectedPaths.length; i++) {
  127. String srcPath = expectedPaths[i];
  128. if (!LangUtil.isEmpty(srcPath)) {
  129. expected.add(org.aspectj.util.FileUtil.weakNormalize(srcPath));
  130. }
  131. }
  132. }
  133. // gather, normalize paths changed
  134. FileFilter touchedCollector = new FileFilter() {
  135. /**
  136. * For files complying with time and suffix rules,
  137. * return true (accumulate - unexpected)
  138. * unless they match expected files,
  139. * (deleting any matches from sources
  140. * so the remainder is missing).
  141. * @return true for unexpected files after date */
  142. public boolean accept(File file) {
  143. if (file.isFile()
  144. && ((0 > startTime)
  145. || (startTime < file.lastModified()))) {
  146. String path = file.getPath();
  147. if ((null == requiredSuffix) || path.endsWith(requiredSuffix)) {
  148. path = org.aspectj.util.FileUtil.weakNormalize(path);
  149. if (checkExpected) {
  150. if (!acceptFilePrefix) {
  151. // File.equals(..) does lexical compare
  152. if (expected.contains(path)) {
  153. expected.remove(path);
  154. // found - do not add to unexpected
  155. return false;
  156. }
  157. } else {
  158. for (Iterator iter = expected.iterator();
  159. iter.hasNext();
  160. ) {
  161. String exp = (String) iter.next();
  162. if (path.startsWith(exp)) {
  163. String suffix = path.substring(exp.length());
  164. if (-1 == suffix.indexOf("/")) { // normalized...
  165. expected.remove(path);
  166. // found - do not add to unexpected
  167. return false;
  168. }
  169. }
  170. }
  171. }
  172. }
  173. // add if is file, right time, and have or don't need suffix
  174. return true;
  175. }
  176. }
  177. // skip if not file or not right time
  178. return false;
  179. }
  180. };
  181. ArrayList unexp = new ArrayList();
  182. unexp.addAll(Arrays.asList(dir.listFiles(touchedCollector)));
  183. // report any unexpected changes
  184. return Diffs.makeDiffs(label, expected, unexp, String.CASE_INSENSITIVE_ORDER);
  185. }
  186. /**
  187. * Visit the entries in a zip file, halting when visitor balks.
  188. * Errors are silently ignored.
  189. * @throws IllegalArgumentException if zipfile or visitor is null
  190. */
  191. public static void visitZipEntries(ZipFile zipfile, StringVisitor visitor) {
  192. visitZipEntries(zipfile, visitor, (StringBuffer) null);
  193. }
  194. /**
  195. * Visit the entries in a zip file, halting when visitor balks.
  196. * Errors are reported in errs, if not null.
  197. * @throws IllegalArgumentException if zipfile or visitor is null
  198. */
  199. public static void visitZipEntries(ZipFile zipfile, StringVisitor visitor,
  200. StringBuffer errs) {
  201. if (null == zipfile) throw new IllegalArgumentException("null zipfile");
  202. if (null == visitor) throw new IllegalArgumentException("null visitor");
  203. int index = 0;
  204. try {
  205. Enumeration enu = zipfile.entries();
  206. while (enu.hasMoreElements()) {
  207. ZipEntry entry = (ZipEntry) enu.nextElement();
  208. index++;
  209. if (! visitor.accept(entry.getName())) {
  210. break;
  211. }
  212. }
  213. } catch (Throwable e) {
  214. if (null != errs) {
  215. errs.append("FileUtil.visitZipEntries error accessing entry " + index
  216. + ": " + e.getMessage());
  217. StringWriter sw = new StringWriter();
  218. e.printStackTrace(new PrintWriter(sw));
  219. errs.append(sw.toString());
  220. }
  221. } finally {
  222. if (null != zipfile) {
  223. try { zipfile.close(); }
  224. catch (IOException x) {} // ignore
  225. }
  226. }
  227. }
  228. /**
  229. * descend filesystem tree, invoking FileFilter.accept() on files.
  230. * E.g., To list files from current directory:
  231. * <code><pre>descendFileTree(new File("."), new FileFilter() {
  232. * public boolean accept(File f){
  233. * System.out.println(f.getAbsolutePath());
  234. * return true;
  235. * }});</code></pre>
  236. * @param file root/starting point. If a file, the only one visited.
  237. * @param filter supplies accept(File) routine
  238. */
  239. public static void descendFileTree(File file, FileFilter filter) {
  240. descendFileTree(file, filter, false);
  241. }
  242. /**
  243. * Descend filesystem tree, invoking FileFilter.accept() on files
  244. * and, if userRecursion, on dirs. If userRecursion, accept() must
  245. * call descendFileTree() again to recurse down directories.
  246. * This calls fileFilter.accept(File) on all files before doing any dirs.
  247. * E.g., To list only files from Unix root:
  248. * <code><pre>descendFileTree(new File("/"), new FileFilter() {
  249. * public boolean run(File f){
  250. * System.out.println(f.getAbsolutePath());
  251. * return true;
  252. * }}, false);</code></pre>
  253. * To list files/dir from root using user recursion:
  254. * <code><pre>descendFileTree(new File("/"), new FileFilter() {
  255. * public boolean run(File f){
  256. * System.out.println(f.getAbsolutePath());
  257. * if (f.isDirectory() && (-1 == f.getName().indexOf("CVS")))
  258. * return descendFileTree(f, this, true);
  259. * return true;
  260. * }}, true);</code></pre>
  261. * @param file root/starting point. If a file, the only one visited.
  262. * @param filter supplies boolean accept(File) method
  263. * @param userRecursion - if true, do accept() on dirs; else, recurse
  264. * @return false if any fileFilter.accept(File) did.
  265. * @throws IllegalArgumentException if file or fileFilter is null
  266. */
  267. public static boolean descendFileTree(File file, FileFilter fileFilter,
  268. boolean userRecursion) {
  269. if (null == file) {throw new IllegalArgumentException("parm File"); }
  270. if (null == fileFilter){throw new IllegalArgumentException("parm FileFilter");}
  271. if (!file.isDirectory()) {
  272. return fileFilter.accept(file);
  273. } else if (file.canRead()) {
  274. // go through files first
  275. File[] files = file.listFiles(ValidFileFilter.FILE_EXISTS);
  276. if (null != files) {
  277. for (int i = 0; i < files.length; i++) {
  278. if (!fileFilter.accept(files[i])) {
  279. return false;
  280. }
  281. }
  282. }
  283. // now recurse to handle directories
  284. File[] dirs = file.listFiles(ValidFileFilter.DIR_EXISTS);
  285. if (null != dirs) {
  286. for (int i = 0; i < dirs.length; i++) {
  287. if (userRecursion) {
  288. if (!fileFilter.accept(dirs[i])) {
  289. return false;
  290. }
  291. } else {
  292. if (!descendFileTree(dirs[i], fileFilter,userRecursion)) {
  293. return false;
  294. }
  295. }
  296. }
  297. }
  298. } // readable directory (ignore unreadable ones)
  299. return true;
  300. } // descendFiles
  301. /**
  302. * Return the names of all files below a directory.
  303. * If file is a directory, then all files under the directory
  304. * are returned. If file is absolute or relative, all the files are.
  305. * If file is a zip or jar file, then all entries in the zip or jar
  306. * are listed. Entries inside those jarfiles/zipfiles are not listed.
  307. * There are no guarantees about ordering.
  308. * @param dir the File to list for
  309. * @param results the Collection to use for the results (may be null)
  310. * @throws IllegalArgumentException if null == dir
  311. * @return a Collection of String of paths, including paths inside jars
  312. */
  313. public static Collection<String> directoryToString(File dir, Collection results) {
  314. if (null == dir) throw new IllegalArgumentException("null dir");
  315. final Collection<String> result = (results != null? results : new Vector());
  316. if (isZipFile(dir)) {
  317. zipFileToString(dir, result);
  318. } else if (!dir.isDirectory()) {
  319. throw new IllegalArgumentException("not a dir: " + dir);
  320. } else {
  321. AccumulatingFileFilter acFilter = new AccumulatingFileFilter() {
  322. public boolean accumulate(File file) {
  323. String name = file.getPath();
  324. result.add(name);
  325. if (isZipFile(file)) {
  326. zipFileToString(file, result);
  327. }
  328. return true;
  329. }
  330. };
  331. descendFileTree(dir, acFilter, false);
  332. }
  333. return result;
  334. } // directoryToString
  335. /**
  336. * Render as String the entries in a zip or jar file,
  337. * converting each to String beforehand (as jarpath!jarentry)
  338. * applying policies for whitespace, etc.
  339. * @param file the File to enumerate ZipEntry for
  340. * @param results the Colection to use to return the FileLine - may be null
  341. * @return FileLines with string as text and
  342. * canonical as string modified by any canonicalizing policies.
  343. */
  344. public static Collection zipFileToString(final File zipfile, Collection results) {
  345. Collection result = (results != null ? results : new Vector());
  346. ZipFile zip = null;
  347. try {
  348. zip = new ZipFile(zipfile); // ZipFile.OPEN_READ| ZipFile.OPEN_DELETE); delete is 1.3 only
  349. Enumeration enu = zip.entries();
  350. while (enu.hasMoreElements()) {
  351. results.add(renderZipEntry(zipfile, (ZipEntry) enu.nextElement()));
  352. }
  353. zip.close();
  354. zip = null;
  355. } catch (Throwable t) {
  356. String err = "Error opening " + zipfile + " attempting to continue...";
  357. System.err.println(err);
  358. t.printStackTrace(System.err);
  359. } finally {
  360. if (null != zip) {
  361. try { zip.close(); }
  362. catch (IOException e) {
  363. e.printStackTrace(System.err);
  364. }
  365. }
  366. }
  367. return result;
  368. }
  369. /**
  370. * @return true if file represents an existing file with a zip extension
  371. */
  372. public static boolean isZipFile(File f) {
  373. String s = null;
  374. if ((null == f) || (null == (s = f.getPath()))) {
  375. return false;
  376. } else {
  377. return (f.canRead() && !f.isDirectory()
  378. && (s.endsWith(".zip")
  379. || (s.endsWith(".jar"))));
  380. }
  381. }
  382. /**
  383. * Render a zip/entry combination to String
  384. */
  385. public static String renderZipEntry(File zipfile, ZipEntry entry) {
  386. String filename = (null == zipfile ? "null File" : zipfile.getName());
  387. String entryname = (null == entry ? "null ZipEntry" : entry.getName());
  388. return filename + "!" + entryname;
  389. }
  390. /**
  391. * Write all files in directory out to jarFile
  392. * @param jarFile the File to create and write to
  393. * @param directory the File representing the directory to read
  394. * @param mainClass the value of the main class attribute - may be null
  395. */
  396. public static boolean createJarFile(File jarFile, File directory,
  397. String mainClass, FileFilter filter) {
  398. String label = "createJarFile("+jarFile
  399. +","+directory +","+mainClass +","+filter + "): ";
  400. Log.signal(label + " start");
  401. if (null == directory)
  402. throw new IllegalArgumentException("null directory");
  403. Manifest manifest = createManifest(mainClass);
  404. Log.signal(label + " manifest=" + manifest);
  405. JarOutputStream out = null;
  406. try {
  407. File jarFileDir = jarFile.getParentFile();
  408. if (null == jarFileDir) {
  409. Log.signal(label + " null jarFileDir");
  410. } else if (!jarFileDir.exists() && !jarFileDir.mkdirs()) { // XXX convert to Error
  411. Log.signal(label + " unable to create jarFileDir: " + jarFileDir);
  412. }
  413. OutputStream os = new FileOutputStream(jarFile);
  414. out = (null == manifest ? new JarOutputStream(os)
  415. : new JarOutputStream(os, manifest));
  416. Log.signal(label + " out=" + out);
  417. ZipAccumulator reader = new ZipAccumulator(directory, out, filter);
  418. Log.signal(label + " reader=" + reader);
  419. FileUtil.descendFileTree(directory, reader);
  420. out.closeEntry();
  421. return true;
  422. } catch (IOException e) {
  423. e.printStackTrace(System.err); // todo
  424. } finally {
  425. if (null != out) {
  426. try { out.close();}
  427. catch (IOException e) {} // todo ignored
  428. }
  429. }
  430. return false;
  431. }
  432. protected static Manifest createManifest(String mainClass) {
  433. final String mainKey = "Main-Class";
  434. Manifest result = null;
  435. if (null != mainClass) {
  436. String entry = "Manifest-Version: 1.0\n"
  437. + mainKey + ": " + mainClass + "\n";
  438. try {
  439. result = new Manifest(new StringBufferInputStream(entry));
  440. Attributes attributes = result.getMainAttributes();
  441. String main = attributes.getValue(mainKey);
  442. if (null == main) {
  443. attributes.putValue(mainKey, mainClass);
  444. main = attributes.getValue(mainKey);
  445. if (null == main) {
  446. Log.signal("createManifest unable to set main "
  447. + mainClass);
  448. }
  449. }
  450. } catch (IOException e) { // todo ignoring
  451. Log.signal(e, " IOException creating manifest with " + mainClass);
  452. }
  453. }
  454. return result;
  455. }
  456. /** read a file out to the zip stream */
  457. protected static void addFileToZip(File in, File parent,
  458. ZipOutputStream out)
  459. throws IOException {
  460. String path = in.getCanonicalPath();
  461. String parentPath = parent.getCanonicalPath();
  462. if (!path.startsWith(parentPath)) {
  463. throw new Error("not parent: " + parentPath + " of " + path);
  464. } else {
  465. path = path.substring(1+parentPath.length());
  466. path = path.replace('\\', '/'); // todo: use filesep
  467. }
  468. ZipEntry entry = new ZipEntry(path);
  469. entry.setTime(in.lastModified());
  470. // todo: default behavior is DEFLATED
  471. out.putNextEntry(entry);
  472. InputStream input = null;
  473. try {
  474. input = new FileInputStream(in);
  475. byte[] buf = new byte[1024];
  476. int count;
  477. while (0 < (count = input.read(buf, 0, buf.length))) {
  478. out.write(buf, 0, count);
  479. }
  480. } finally {
  481. if (null != input) input.close();
  482. }
  483. }
  484. public static void returnTempDir(File dir) {
  485. deleteDirectory(dir);
  486. }
  487. /** @return true if path ends with gif, properties, jpg */
  488. public static boolean isResourcePath(String path) {
  489. if (null == path) return false;
  490. path = path.toLowerCase();
  491. return (path.endsWith(".gif")
  492. || path.endsWith(".properties")
  493. || path.endsWith(".jpg")
  494. || path.endsWith(".jpeg")
  495. || path.endsWith(".props")
  496. );
  497. }
  498. public static void render(Throwable t, StringBuffer err) { // todo: move
  499. String name = t.getClass().getName();
  500. int loc = name.lastIndexOf(".");
  501. name = name.substring(1+loc);
  502. err.append(name + ": " + t.getMessage() + "\n"); // todo
  503. StringWriter sw = new StringWriter();
  504. t.printStackTrace(new PrintWriter(sw));
  505. err.append(sw.toString());
  506. }
  507. private static boolean report(StringBuffer err, String context, String status,
  508. Throwable throwable) {
  509. boolean failed = ((null != status) || (null != throwable));
  510. if ((null != err) && (failed)) {
  511. if (null != context) {
  512. err.append(context);
  513. }
  514. if (null != status) {
  515. err.append(status);
  516. }
  517. if (null != throwable) {
  518. render(throwable, err);
  519. }
  520. }
  521. return failed;
  522. }
  523. /**
  524. * Copy file.
  525. * @param src the File to copy - must exist
  526. * @param dest the File for the target file or directory (will not create directories)
  527. * @param err the StringBuffer for returning any errors - may be null
  528. **/
  529. public static boolean copyFile(File src, File dest, StringBuffer err) {
  530. boolean result = false;
  531. String label = "start";
  532. Throwable throwable = null;
  533. try {
  534. if (!ValidFileFilter.FILE_EXISTS.accept(src)) {
  535. label = "src file does not exist";
  536. } else {
  537. if (dest.isDirectory()) {
  538. dest = new File(dest, src.getName());
  539. }
  540. if (ValidFileFilter.FILE_EXISTS.accept(dest)) {
  541. label = "dest file exists";
  542. }
  543. boolean closeWhenDone = true;
  544. result = copy(new FileInputStream(src),
  545. new FileOutputStream(dest),
  546. closeWhenDone);
  547. }
  548. label = null;
  549. } catch (Throwable t) {
  550. throwable = t;
  551. }
  552. String context = "FileUtil.copyFile(src, dest, err)";
  553. boolean report = report(err, context, label, throwable);
  554. return (result && !report);
  555. }
  556. /**
  557. * Copy URL to file.
  558. * @param src the URL to copy - must exist
  559. * @param dest the File for the target file or directory (will not create directories)
  560. * @param err the StringBuffer for returning any errors - may be null
  561. **/
  562. public static boolean copyURL(URL url, File dest, StringBuffer err) { // todo untested.
  563. boolean result = false;
  564. String label = "start";
  565. Throwable throwable = null;
  566. try {
  567. if (dest.isDirectory()) {
  568. String filename = url.getFile();
  569. if ((null == filename) || (0 == filename.length())) {
  570. filename = DEFAULT_URL_FILENAME;
  571. }
  572. dest = new File(dest, filename);
  573. }
  574. if (ValidFileFilter.FILE_EXISTS.accept(dest)) {
  575. label = "dest file exists";
  576. }
  577. boolean closeWhenDone = true;
  578. result = copy(url.openConnection().getInputStream(),
  579. new FileOutputStream(dest),
  580. closeWhenDone);
  581. label = null;
  582. } catch (Throwable t) {
  583. throwable = t;
  584. }
  585. String context = "FileUtil.copyURL(src, dest, err)"; // add actual parm to labels?
  586. boolean report = report(err, context, label, throwable);
  587. return (result && report);
  588. }
  589. /**
  590. * Copy input to output - does not close either
  591. * @param src the InputStream to copy - must exist
  592. * @param dest the OutputStream for the target
  593. * @param close if true, close when done
  594. */
  595. public static boolean copy(InputStream src, OutputStream dest,
  596. boolean close)
  597. throws IOException {
  598. boolean result = false;
  599. IOException throwable = null;
  600. try {
  601. byte[] buf = new byte[8*1024];
  602. int count;
  603. while (0 < (count = src.read(buf, 0, buf.length))) {
  604. dest.write(buf, 0, count);
  605. }
  606. result = true;
  607. } catch (IOException t) {
  608. throwable = t;
  609. } finally {
  610. if (close) {
  611. try { if (null != src) src.close(); }
  612. catch (IOException e) {
  613. if (null == throwable) { throwable = e; }
  614. }
  615. try { if (null != dest) dest.close(); }
  616. catch (IOException i) {
  617. if (null == throwable) { throwable = i; }
  618. }
  619. }
  620. }
  621. if (null != throwable) throw throwable;
  622. return result;
  623. }
  624. /**
  625. * @return true if dir was an existing directory that is now deleted
  626. */
  627. protected static boolean deleteDirectory(File dir) {
  628. return ((null != dir)
  629. && dir.exists()
  630. && dir.isDirectory()
  631. && FileUtil.descendFileTree(dir, DELETE_FILES, false)
  632. && FileUtil.descendFileTree(dir, DELETE_DIRS, true)
  633. && dir.delete());
  634. }
  635. public static String[] getPaths(File[] files) { // util
  636. String[] result = new String[files.length];
  637. for (int i = 0; i < result.length; i++) {
  638. result[i] = files[i].getPath(); // preserves absolute?
  639. }
  640. return result;
  641. }
  642. //-------- first-order, input and visible interface
  643. protected static final FileFilter DELETE_DIRS = new FileFilter() {
  644. public boolean accept(File file) {
  645. return ((null != file) && file.isDirectory()
  646. && file.exists() && file.delete());
  647. }
  648. };
  649. protected static final FileFilter DELETE_FILES = new FileFilter() {
  650. public boolean accept(File file) {
  651. return ((null != file) && !file.isDirectory()
  652. && file.exists() && file.delete());
  653. }
  654. };
  655. } // class FileUtil
  656. /**
  657. * Localize FileUtil log/signals for now
  658. * ordinary signals are ignored,
  659. * but exceptions are printed to err
  660. * and errors are thrown as Error
  661. */
  662. class Log {
  663. /** ordinary logging - may be suppressed */
  664. public static final void signal(String s) {
  665. //System.err.println(s);
  666. }
  667. /** print stack trace to System.err */
  668. public static final void signal(Throwable t, String s) {
  669. System.err.println(s);
  670. t.printStackTrace(System.err);
  671. }
  672. /** @throws Error(s) always */
  673. public static final void error(String s) {
  674. throw new Error(s);
  675. }
  676. }
  677. /** read each file out to the zip file */
  678. class ZipAccumulator implements FileFilter {
  679. final File parentDir;
  680. final ZipOutputStream out;
  681. final FileFilter filter;
  682. public ZipAccumulator(File parentDir, ZipOutputStream out,
  683. FileFilter filter) {
  684. this.parentDir = parentDir;
  685. this.out = out;
  686. this.filter = filter;
  687. }
  688. public boolean accept(File f) {
  689. if ((null != filter) && (!filter.accept(f))) {
  690. return false;
  691. }
  692. try {
  693. FileUtil.addFileToZip(f, parentDir, out);
  694. return true;
  695. } catch (IOException e) {
  696. e.printStackTrace(System.err); // todo
  697. }
  698. return false;
  699. }
  700. }