Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

FileUtil.java 47KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.util;
  14. import java.io.BufferedOutputStream;
  15. import java.io.BufferedReader;
  16. import java.io.ByteArrayOutputStream;
  17. import java.io.DataInputStream;
  18. import java.io.DataOutputStream;
  19. import java.io.File;
  20. import java.io.FileFilter;
  21. import java.io.FileInputStream;
  22. import java.io.FileNotFoundException;
  23. import java.io.FileOutputStream;
  24. import java.io.FileReader;
  25. import java.io.FileWriter;
  26. import java.io.FilenameFilter;
  27. import java.io.IOException;
  28. import java.io.InputStream;
  29. import java.io.OutputStream;
  30. import java.io.PrintStream;
  31. import java.io.Reader;
  32. import java.io.StringReader;
  33. import java.io.Writer;
  34. import java.net.MalformedURLException;
  35. import java.net.URISyntaxException;
  36. import java.net.URL;
  37. import java.util.ArrayList;
  38. import java.util.Arrays;
  39. import java.util.Collections;
  40. import java.util.Iterator;
  41. import java.util.LinkedList;
  42. import java.util.List;
  43. import java.util.zip.ZipEntry;
  44. import java.util.zip.ZipFile;
  45. /**
  46. * @author Andy Clement
  47. * @author Kris De Volder
  48. */
  49. public class FileUtil {
  50. /** default parent directory File when a file has a null parent */
  51. public static final File DEFAULT_PARENT = new File("."); // XXX user.dir?
  52. /** unmodifiable List of String source file suffixes (including leading ".") */
  53. public static final List<String> SOURCE_SUFFIXES = Collections.unmodifiableList(Arrays.asList(new String[] { ".java", ".aj" }));
  54. public static final FileFilter ZIP_FILTER = new FileFilter() {
  55. public boolean accept(File file) {
  56. return isZipFile(file);
  57. }
  58. public String toString() {
  59. return "ZIP_FILTER";
  60. }
  61. };
  62. // public static final FileFilter SOURCE_FILTER = new FileFilter() {
  63. // public boolean accept(File file) {
  64. // return hasSourceSuffix(file);
  65. // }
  66. //
  67. // public String toString() {
  68. // return "SOURCE_FILTER";
  69. // }
  70. // };
  71. final static int[] INT_RA = new int[0];
  72. /** accept all files */
  73. public static final FileFilter ALL = new FileFilter() {
  74. public boolean accept(File f) {
  75. return true;
  76. }
  77. };
  78. public static final FileFilter DIRS_AND_WRITABLE_CLASSES = new FileFilter() {
  79. public boolean accept(File file) {
  80. return ((null != file) && (file.isDirectory() || (file.canWrite() && file.getName().toLowerCase().endsWith(".class"))));
  81. }
  82. };
  83. private static final boolean PERMIT_CVS;
  84. static {
  85. String name = FileUtil.class.getName() + ".PERMIT_CVS";
  86. PERMIT_CVS = LangUtil.getBoolean(name, false);
  87. }
  88. /** @return true if file exists and is a zip file */
  89. public static boolean isZipFile(File file) {
  90. try {
  91. return (null != file) && new ZipFile(file) != null;
  92. } catch (IOException e) {
  93. return false;
  94. }
  95. }
  96. /** @return true if path ends with .zip or .jar */
  97. // public static boolean hasZipSuffix(String path) {
  98. // return ((null != path) && (0 != zipSuffixLength(path)));
  99. // }
  100. /** @return 0 if file has no zip/jar suffix or 4 otherwise */
  101. public static int zipSuffixLength(File file) {
  102. return (null == file ? 0 : zipSuffixLength(file.getPath()));
  103. }
  104. /** @return 0 if no zip/jar suffix or 4 otherwise */
  105. public static int zipSuffixLength(String path) {
  106. if ((null != path) && (4 < path.length())) {
  107. String test = path.substring(path.length() - 4).toLowerCase();
  108. if (".zip".equals(test) || ".jar".equals(test)) {
  109. return 4;
  110. }
  111. }
  112. return 0;
  113. }
  114. /** @return true if file path has a source suffix */
  115. public static boolean hasSourceSuffix(File file) {
  116. return ((null != file) && hasSourceSuffix(file.getPath()));
  117. }
  118. /** @return true if path ends with .java or .aj */
  119. public static boolean hasSourceSuffix(String path) {
  120. return ((null != path) && (0 != sourceSuffixLength(path)));
  121. }
  122. /**
  123. * @return 0 if file has no source suffix or the length of the suffix otherwise
  124. */
  125. public static int sourceSuffixLength(File file) {
  126. return (null == file ? 0 : sourceSuffixLength(file.getPath()));
  127. }
  128. /** @return 0 if no source suffix or the length of the suffix otherwise */
  129. public static int sourceSuffixLength(String path) {
  130. if (LangUtil.isEmpty(path)) {
  131. return 0;
  132. }
  133. for (Iterator<String> iter = SOURCE_SUFFIXES.iterator(); iter.hasNext();) {
  134. String suffix = iter.next();
  135. if (path.endsWith(suffix) || path.toLowerCase().endsWith(suffix)) {
  136. return suffix.length();
  137. }
  138. }
  139. return 0;
  140. }
  141. /** @return true if this is a readable directory */
  142. public static boolean canReadDir(File dir) {
  143. return ((null != dir) && dir.canRead() && dir.isDirectory());
  144. }
  145. /** @return true if this is a readable file */
  146. public static boolean canReadFile(File file) {
  147. return ((null != file) && file.canRead() && file.isFile());
  148. }
  149. /** @return true if dir is a writable directory */
  150. public static boolean canWriteDir(File dir) {
  151. return ((null != dir) && dir.canWrite() && dir.isDirectory());
  152. }
  153. /** @return true if this is a writable file */
  154. public static boolean canWriteFile(File file) {
  155. return ((null != file) && file.canWrite() && file.isFile());
  156. }
  157. // /**
  158. // * @throws IllegalArgumentException unless file is readable and not a
  159. // * directory
  160. // */
  161. // public static void throwIaxUnlessCanReadFile(File file, String label) {
  162. // if (!canReadFile(file)) {
  163. // throw new IllegalArgumentException(label + " not readable file: " +
  164. // file);
  165. // }
  166. // }
  167. /**
  168. * @throws IllegalArgumentException unless dir is a readable directory
  169. */
  170. public static void throwIaxUnlessCanReadDir(File dir, String label) {
  171. if (!canReadDir(dir)) {
  172. throw new IllegalArgumentException(label + " not readable dir: " + dir);
  173. }
  174. }
  175. /**
  176. * @throws IllegalArgumentException unless file is readable and not a directory
  177. */
  178. public static void throwIaxUnlessCanWriteFile(File file, String label) {
  179. if (!canWriteFile(file)) {
  180. throw new IllegalArgumentException(label + " not writable file: " + file);
  181. }
  182. }
  183. /** @throws IllegalArgumentException unless dir is a readable directory */
  184. public static void throwIaxUnlessCanWriteDir(File dir, String label) {
  185. if (!canWriteDir(dir)) {
  186. throw new IllegalArgumentException(label + " not writable dir: " + dir);
  187. }
  188. }
  189. /** @return array same length as input, with String paths */
  190. public static String[] getPaths(File[] files) {
  191. if ((null == files) || (0 == files.length)) {
  192. return new String[0];
  193. }
  194. String[] result = new String[files.length];
  195. for (int i = 0; i < result.length; i++) {
  196. if (null != files[i]) {
  197. result[i] = files[i].getPath();
  198. }
  199. }
  200. return result;
  201. }
  202. /** @return array same length as input, with String paths */
  203. public static String[] getPaths(List<File> files) {
  204. final int size = (null == files ? 0 : files.size());
  205. if (0 == size) {
  206. return new String[0];
  207. }
  208. String[] result = new String[size];
  209. for (int i = 0; i < size; i++) {
  210. File file = files.get(i);
  211. if (null != file) {
  212. result[i] = file.getPath();
  213. }
  214. }
  215. return result;
  216. }
  217. /**
  218. * Extract the name of a class from the path to its file. If the basedir is null, then the class is assumed to be in the default
  219. * package unless the classFile has one of the top-level suffixes { com, org, java, javax } as a parent directory.
  220. *
  221. * @param basedir the File of the base directory (prefix of classFile)
  222. * @param classFile the File of the class to extract the name for
  223. * @throws IllegalArgumentException if classFile is null or does not end with ".class" or a non-null basedir is not a prefix of
  224. * classFile
  225. */
  226. public static String fileToClassName(File basedir, File classFile) {
  227. LangUtil.throwIaxIfNull(classFile, "classFile");
  228. String classFilePath = normalizedPath(classFile);
  229. if (!classFilePath.endsWith(".class")) {
  230. String m = classFile + " does not end with .class";
  231. throw new IllegalArgumentException(m);
  232. }
  233. classFilePath = classFilePath.substring(0, classFilePath.length() - 6);
  234. if (null != basedir) {
  235. String basePath = normalizedPath(basedir);
  236. if (!classFilePath.startsWith(basePath)) {
  237. String m = classFile + " does not start with " + basedir;
  238. throw new IllegalArgumentException(m);
  239. }
  240. classFilePath = classFilePath.substring(basePath.length() + 1);
  241. } else {
  242. final String[] suffixes = new String[] { "com", "org", "java", "javax" };
  243. boolean found = false;
  244. for (int i = 0; !found && (i < suffixes.length); i++) {
  245. int loc = classFilePath.indexOf(suffixes[i] + "/");
  246. if ((0 == loc) || ((-1 != loc) && ('/' == classFilePath.charAt(loc - 1)))) {
  247. classFilePath = classFilePath.substring(loc);
  248. found = true;
  249. }
  250. }
  251. if (!found) {
  252. int loc = classFilePath.lastIndexOf("/");
  253. if (-1 != loc) { // treat as default package
  254. classFilePath = classFilePath.substring(loc + 1);
  255. }
  256. }
  257. }
  258. return classFilePath.replace('/', '.');
  259. }
  260. /**
  261. * Normalize path for comparisons by rendering absolute, clipping basedir prefix, trimming and changing '\\' to '/'
  262. *
  263. * @param file the File with the path to normalize
  264. * @param basedir the File for the prefix of the file to normalize - ignored if null
  265. * @return "" if null or normalized path otherwise
  266. * @throws IllegalArgumentException if basedir is not a prefix of file
  267. */
  268. public static String normalizedPath(File file, File basedir) {
  269. String filePath = normalizedPath(file);
  270. if (null != basedir) {
  271. String basePath = normalizedPath(basedir);
  272. if (filePath.startsWith(basePath)) {
  273. filePath = filePath.substring(basePath.length());
  274. if (filePath.startsWith("/")) {
  275. filePath = filePath.substring(1);
  276. }
  277. }
  278. }
  279. return filePath;
  280. }
  281. /**
  282. * Render a set of files to String as a path by getting absolute paths of each and delimiting with infix.
  283. *
  284. * @param files the File[] to flatten - may be null or empty
  285. * @param infix the String delimiter internally between entries (if null, then use File.pathSeparator). (alias to
  286. * <code>flatten(getAbsolutePaths(files), infix)</code>
  287. * @return String with absolute paths to entries in order, delimited with infix
  288. */
  289. public static String flatten(File[] files, String infix) {
  290. if (LangUtil.isEmpty(files)) {
  291. return "";
  292. }
  293. return flatten(getPaths(files), infix);
  294. }
  295. /**
  296. * Flatten File[] to String.
  297. *
  298. * @param files the File[] of paths to flatten - null ignored
  299. * @param infix the String infix to use - null treated as File.pathSeparator
  300. */
  301. public static String flatten(String[] paths, String infix) {
  302. if (null == infix) {
  303. infix = File.pathSeparator;
  304. }
  305. StringBuffer result = new StringBuffer();
  306. boolean first = true;
  307. for (int i = 0; i < paths.length; i++) {
  308. String path = paths[i];
  309. if (null == path) {
  310. continue;
  311. }
  312. if (first) {
  313. first = false;
  314. } else {
  315. result.append(infix);
  316. }
  317. result.append(path);
  318. }
  319. return result.toString();
  320. }
  321. /**
  322. * Normalize path for comparisons by rendering absolute trimming and changing '\\' to '/'
  323. *
  324. * @return "" if null or normalized path otherwise
  325. */
  326. public static String normalizedPath(File file) {
  327. return (null == file ? "" : weakNormalize(file.getAbsolutePath()));
  328. }
  329. /**
  330. * Weakly normalize path for comparisons by trimming and changing '\\' to '/'
  331. */
  332. public static String weakNormalize(String path) {
  333. if (null != path) {
  334. path = path.replace('\\', '/').trim();
  335. }
  336. return path;
  337. }
  338. /**
  339. * Get best File for the first-readable path in input paths, treating entries prefixed "sp:" as system property keys. Safe to
  340. * call in static initializers.
  341. *
  342. * @param paths the String[] of paths to check.
  343. * @return null if not found, or valid File otherwise
  344. */
  345. public static File getBestFile(String[] paths) {
  346. if (null == paths) {
  347. return null;
  348. }
  349. File result = null;
  350. for (int i = 0; (null == result) && (i < paths.length); i++) {
  351. String path = paths[i];
  352. if (null == path) {
  353. continue;
  354. }
  355. if (path.startsWith("sp:")) {
  356. try {
  357. path = System.getProperty(path.substring(3));
  358. } catch (Throwable t) {
  359. path = null;
  360. }
  361. if (null == path) {
  362. continue;
  363. }
  364. }
  365. try {
  366. File f = new File(path);
  367. if (f.exists() && f.canRead()) {
  368. result = FileUtil.getBestFile(f);
  369. }
  370. } catch (Throwable t) {
  371. // swallow
  372. }
  373. }
  374. return result;
  375. }
  376. /**
  377. * Render as best file, canonical or absolute.
  378. *
  379. * @param file the File to get the best File for (not null)
  380. * @return File of the best-available path
  381. * @throws IllegalArgumentException if file is null
  382. */
  383. public static File getBestFile(File file) {
  384. LangUtil.throwIaxIfNull(file, "file");
  385. if (file.exists()) {
  386. try {
  387. return file.getCanonicalFile();
  388. } catch (IOException e) {
  389. return file.getAbsoluteFile();
  390. }
  391. } else {
  392. return file;
  393. }
  394. }
  395. /**
  396. * Render as best path, canonical or absolute.
  397. *
  398. * @param file the File to get the path for (not null)
  399. * @return String of the best-available path
  400. * @throws IllegalArgumentException if file is null
  401. */
  402. public static String getBestPath(File file) {
  403. LangUtil.throwIaxIfNull(file, "file");
  404. if (file.exists()) {
  405. try {
  406. return file.getCanonicalPath();
  407. } catch (IOException e) {
  408. return file.getAbsolutePath();
  409. }
  410. } else {
  411. return file.getPath();
  412. }
  413. }
  414. /** @return array same length as input, with String absolute paths */
  415. public static String[] getAbsolutePaths(File[] files) {
  416. if ((null == files) || (0 == files.length)) {
  417. return new String[0];
  418. }
  419. String[] result = new String[files.length];
  420. for (int i = 0; i < result.length; i++) {
  421. if (null != files[i]) {
  422. result[i] = files[i].getAbsolutePath();
  423. }
  424. }
  425. return result;
  426. }
  427. /**
  428. * Recursively delete the contents of dir, but not the dir itself
  429. *
  430. * @return the total number of files deleted
  431. */
  432. public static int deleteContents(File dir) {
  433. return deleteContents(dir, ALL);
  434. }
  435. /**
  436. * Recursively delete some contents of dir, but not the dir itself. This deletes any subdirectory which is empty after its files
  437. * are deleted.
  438. *
  439. * @return the total number of files deleted
  440. */
  441. public static int deleteContents(File dir, FileFilter filter) {
  442. return deleteContents(dir, filter, true);
  443. }
  444. /**
  445. * Recursively delete some contents of dir, but not the dir itself. If deleteEmptyDirs is true, this deletes any subdirectory
  446. * which is empty after its files are deleted.
  447. *
  448. * @param dir the File directory (if a file, the the file is deleted)
  449. * @return the total number of files deleted
  450. */
  451. public static int deleteContents(File dir, FileFilter filter,
  452. boolean deleteEmptyDirs) {
  453. if (null == dir) {
  454. throw new IllegalArgumentException("null dir");
  455. }
  456. if ((!dir.exists()) || (!dir.canWrite())) {
  457. return 0;
  458. }
  459. if (!dir.isDirectory()) {
  460. dir.delete();
  461. return 1;
  462. }
  463. String[] fromFiles = dir.list();
  464. if (fromFiles == null) {
  465. return 0;
  466. }
  467. int result = 0;
  468. for (int i = 0; i < fromFiles.length; i++) {
  469. String string = fromFiles[i];
  470. File file = new File(dir, string);
  471. if ((null == filter) || filter.accept(file)) {
  472. if (file.isDirectory()) {
  473. result += deleteContents(file, filter, deleteEmptyDirs);
  474. String[] fileContent = file.list();
  475. if (deleteEmptyDirs && fileContent != null
  476. && 0 == fileContent.length) {
  477. file.delete();
  478. }
  479. } else {
  480. /* boolean ret = */
  481. file.delete();
  482. result++;
  483. }
  484. }
  485. }
  486. return result;
  487. }
  488. /**
  489. * Copy contents of fromDir into toDir
  490. *
  491. * @param fromDir must exist and be readable
  492. * @param toDir must exist or be creatable and be writable
  493. * @return the total number of files copied
  494. */
  495. public static int copyDir(File fromDir, File toDir) throws IOException {
  496. return copyDir(fromDir, toDir, null, null);
  497. }
  498. /**
  499. * Recursively copy files in fromDir (with any fromSuffix) to toDir, replacing fromSuffix with toSuffix if any. This silently
  500. * ignores dirs and files that are not readable but throw IOException for directories that are not writable. This does not clean
  501. * out the original contents of toDir. (subdirectories are not renamed per directory rules)
  502. *
  503. * @param fromSuffix select files with this suffix - select all if null or empty
  504. * @param toSuffix replace fromSuffix with toSuffix in the destination file name - ignored if null or empty, appended to name if
  505. * fromSuffix is null or empty
  506. * @return the total number of files copied
  507. */
  508. public static int copyDir(File fromDir, File toDir, final String fromSuffix, String toSuffix) throws IOException {
  509. return copyDir(fromDir, toDir, fromSuffix, toSuffix, (FileFilter) null);
  510. }
  511. // /**
  512. // * Recursively copy files in fromDir (with any fromSuffix) to toDir,
  513. // * replacing fromSuffix with toSuffix if any, and adding the destination
  514. // * file to any collector. This silently ignores dirs and files that are
  515. // not
  516. // * readable but throw IOException for directories that are not writable.
  517. // * This does not clean out the original contents of toDir. (subdirectories
  518. // * are not renamed per directory rules) This calls any delegate
  519. // * FilenameFilter to collect any selected file.
  520. // *
  521. // * @param fromSuffix select files with this suffix - select all if null or
  522. // * empty
  523. // * @param toSuffix replace fromSuffix with toSuffix in the destination
  524. // file
  525. // * name - ignored if null or empty, appended to name if
  526. // * fromSuffix is null or empty
  527. // * @param collector the List sink for destination files - ignored if null
  528. // * @return the total number of files copied
  529. // */
  530. // public static int copyDir(File fromDir, File toDir, final String
  531. // fromSuffix, final String toSuffix, final List collector)
  532. // throws IOException {
  533. // // int before = collector.size();
  534. // if (null == collector) {
  535. // return copyDir(fromDir, toDir, fromSuffix, toSuffix);
  536. // } else {
  537. // FileFilter collect = new FileFilter() {
  538. // public boolean accept(File pathname) {
  539. // return collector.add(pathname);
  540. // }
  541. // };
  542. // return copyDir(fromDir, toDir, fromSuffix, toSuffix, collect);
  543. // }
  544. // }
  545. /**
  546. * Recursively copy files in fromDir (with any fromSuffix) to toDir, replacing fromSuffix with toSuffix if any. This silently
  547. * ignores dirs and files that are not readable but throw IOException for directories that are not writable. This does not clean
  548. * out the original contents of toDir. (subdirectories are not renamed per directory rules) This calls any delegate
  549. * FilenameFilter to collect any selected file.
  550. *
  551. * @param fromSuffix select files with this suffix - select all if null or empty
  552. * @param toSuffix replace fromSuffix with toSuffix in the destination file name - ignored if null or empty, appended to name if
  553. * fromSuffix is null or empty
  554. * @return the total number of files copied
  555. */
  556. public static int copyDir(File fromDir, File toDir, final String fromSuffix, final String toSuffix, final FileFilter delegate)
  557. throws IOException {
  558. if ((null == fromDir) || (!fromDir.canRead())) {
  559. return 0;
  560. }
  561. final boolean haveSuffix = ((null != fromSuffix) && (0 < fromSuffix.length()));
  562. final int slen = (!haveSuffix ? 0 : fromSuffix.length());
  563. if (!toDir.exists()) {
  564. toDir.mkdirs();
  565. }
  566. final String[] fromFiles;
  567. if (!haveSuffix) {
  568. fromFiles = fromDir.list();
  569. } else {
  570. FilenameFilter filter = new FilenameFilter() {
  571. public boolean accept(File dir, String name) {
  572. return (new File(dir, name).isDirectory() || (name.endsWith(fromSuffix)));
  573. }
  574. };
  575. fromFiles = fromDir.list(filter);
  576. }
  577. int result = 0;
  578. final int MAX = (null == fromFiles ? 0 : fromFiles.length);
  579. for (int i = 0; i < MAX; i++) {
  580. String filename = fromFiles[i];
  581. File fromFile = new File(fromDir, filename);
  582. if (fromFile.canRead()) {
  583. if (fromFile.isDirectory()) {
  584. result += copyDir(fromFile, new File(toDir, filename), fromSuffix, toSuffix, delegate);
  585. } else if (fromFile.isFile()) {
  586. if (haveSuffix) {
  587. filename = filename.substring(0, filename.length() - slen);
  588. }
  589. if (null != toSuffix) {
  590. filename = filename + toSuffix;
  591. }
  592. File targetFile = new File(toDir, filename);
  593. if ((null == delegate) || delegate.accept(targetFile)) {
  594. copyFile(fromFile, targetFile);
  595. }
  596. result++;
  597. }
  598. }
  599. }
  600. return result;
  601. }
  602. /**
  603. * Recursively list files in srcDir.
  604. *
  605. * @return ArrayList with String paths of File under srcDir (relative to srcDir)
  606. */
  607. public static String[] listFiles(File srcDir) {
  608. ArrayList<String> result = new ArrayList<String>();
  609. if ((null != srcDir) && srcDir.canRead()) {
  610. listFiles(srcDir, null, result);
  611. }
  612. return result.toArray(new String[0]);
  613. }
  614. public static final FileFilter aspectjSourceFileFilter = new FileFilter() {
  615. public boolean accept(File pathname) {
  616. String name = pathname.getName().toLowerCase();
  617. return name.endsWith(".java") || name.endsWith(".aj");
  618. }
  619. };
  620. /**
  621. * Recursively list files in srcDir.
  622. *
  623. * @return ArrayList with String paths of File under srcDir (relative to srcDir)
  624. */
  625. public static File[] listFiles(File srcDir, FileFilter fileFilter) {
  626. ArrayList<File> result = new ArrayList<File>();
  627. if ((null != srcDir) && srcDir.canRead()) {
  628. listFiles(srcDir, result, fileFilter);
  629. }
  630. return result.toArray(new File[result.size()]);
  631. }
  632. /**
  633. * Recursively list .class files in specified directory
  634. *
  635. * @return List of File objects
  636. */
  637. public static List<File> listClassFiles(File dir) {
  638. ArrayList<File> result = new ArrayList<File>();
  639. if ((null != dir) && dir.canRead()) {
  640. listClassFiles(dir, result);
  641. }
  642. return result;
  643. }
  644. /**
  645. * Convert String[] paths to File[] as offset of base directory
  646. *
  647. * @param basedir the non-null File base directory for File to create with paths
  648. * @param paths the String[] of paths to create
  649. * @return File[] with same length as paths
  650. */
  651. public static File[] getBaseDirFiles(File basedir, String[] paths) {
  652. return getBaseDirFiles(basedir, paths, (String[]) null);
  653. }
  654. /**
  655. * Convert String[] paths to File[] as offset of base directory
  656. *
  657. * @param basedir the non-null File base directory for File to create with paths
  658. * @param paths the String[] of paths to create
  659. * @param suffixes the String[] of suffixes to limit sources to - ignored if null
  660. * @return File[] with same length as paths
  661. */
  662. public static File[] getBaseDirFiles(File basedir, String[] paths, String[] suffixes) {
  663. LangUtil.throwIaxIfNull(basedir, "basedir");
  664. LangUtil.throwIaxIfNull(paths, "paths");
  665. File[] result = null;
  666. if (!LangUtil.isEmpty(suffixes)) {
  667. ArrayList<File> list = new ArrayList<File>();
  668. for (int i = 0; i < paths.length; i++) {
  669. String path = paths[i];
  670. for (int j = 0; j < suffixes.length; j++) {
  671. if (path.endsWith(suffixes[j])) {
  672. list.add(new File(basedir, paths[i]));
  673. break;
  674. }
  675. }
  676. }
  677. result = list.toArray(new File[0]);
  678. } else {
  679. result = new File[paths.length];
  680. for (int i = 0; i < result.length; i++) {
  681. result[i] = newFile(basedir, paths[i]);
  682. }
  683. }
  684. return result;
  685. }
  686. /**
  687. * Create a new File, resolving paths ".." and "." specially.
  688. *
  689. * @param dir the File for the parent directory of the file
  690. * @param path the path in the parent directory (filename only?)
  691. * @return File for the new file.
  692. */
  693. private static File newFile(File dir, String path) {
  694. if (".".equals(path)) {
  695. return dir;
  696. } else if ("..".equals(path)) {
  697. File parentDir = dir.getParentFile();
  698. if (null != parentDir) {
  699. return parentDir;
  700. } else {
  701. return new File(dir, "..");
  702. }
  703. } else {
  704. return new File(dir, path);
  705. }
  706. }
  707. /**
  708. * Copy files from source dir into destination directory, creating any needed directories. This differs from copyDir in not
  709. * being recursive; each input with the source dir creates a full path. However, if the source is a directory, it is copied as
  710. * such.
  711. *
  712. * @param srcDir an existing, readable directory containing relativePaths files
  713. * @param relativePaths a set of paths relative to srcDir to readable File to copy
  714. * @param destDir an existing, writable directory to copy files to
  715. * @throws IllegalArgumentException if input invalid, IOException if operations fail
  716. */
  717. public static File[] copyFiles(File srcDir, String[] relativePaths, File destDir) throws IllegalArgumentException, IOException {
  718. final String[] paths = relativePaths;
  719. throwIaxUnlessCanReadDir(srcDir, "srcDir");
  720. throwIaxUnlessCanWriteDir(destDir, "destDir");
  721. LangUtil.throwIaxIfNull(paths, "relativePaths");
  722. File[] result = new File[paths.length];
  723. for (int i = 0; i < paths.length; i++) {
  724. String path = paths[i];
  725. LangUtil.throwIaxIfNull(path, "relativePaths-entry");
  726. File src = newFile(srcDir, paths[i]);
  727. File dest = newFile(destDir, path);
  728. File destParent = dest.getParentFile();
  729. if (!destParent.exists()) {
  730. destParent.mkdirs();
  731. }
  732. LangUtil.throwIaxIfFalse(canWriteDir(destParent), "dest-entry-parent");
  733. copyFile(src, dest); // both file-dir and dir-dir copies
  734. result[i] = dest;
  735. }
  736. return result;
  737. }
  738. /**
  739. * Copy fromFile to toFile, handling file-file, dir-dir, and file-dir copies.
  740. *
  741. * @param fromFile the File path of the file or directory to copy - must be readable
  742. * @param toFile the File path of the target file or directory - must be writable (will be created if it does not exist)
  743. */
  744. public static void copyFile(File fromFile, File toFile) throws IOException {
  745. LangUtil.throwIaxIfNull(fromFile, "fromFile");
  746. LangUtil.throwIaxIfNull(toFile, "toFile");
  747. LangUtil.throwIaxIfFalse(!toFile.equals(fromFile), "same file");
  748. if (toFile.isDirectory()) { // existing directory
  749. throwIaxUnlessCanWriteDir(toFile, "toFile");
  750. if (fromFile.isFile()) { // file-dir
  751. File targFile = new File(toFile, fromFile.getName());
  752. copyValidFiles(fromFile, targFile);
  753. } else if (fromFile.isDirectory()) { // dir-dir
  754. copyDir(fromFile, toFile);
  755. } else {
  756. LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile);
  757. }
  758. } else if (toFile.isFile()) { // target file exists
  759. if (fromFile.isDirectory()) {
  760. LangUtil.throwIaxIfFalse(false, "can't copy to file dir: " + fromFile);
  761. }
  762. copyValidFiles(fromFile, toFile); // file-file
  763. } else { // target file is a non-existent path -- could be file or dir
  764. /* File toFileParent = */ensureParentWritable(toFile);
  765. if (fromFile.isFile()) {
  766. copyValidFiles(fromFile, toFile);
  767. } else if (fromFile.isDirectory()) {
  768. toFile.mkdirs();
  769. throwIaxUnlessCanWriteDir(toFile, "toFile");
  770. copyDir(fromFile, toFile);
  771. } else {
  772. LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile);
  773. }
  774. }
  775. }
  776. /**
  777. * Ensure that the parent directory to path can be written. If the path has a null parent, DEFAULT_PARENT is tested. If the path
  778. * parent does not exist, this tries to create it.
  779. *
  780. * @param path the File path whose parent should be writable
  781. * @return the File path of the writable parent directory
  782. * @throws IllegalArgumentException if parent cannot be written or path is null.
  783. */
  784. public static File ensureParentWritable(File path) {
  785. LangUtil.throwIaxIfNull(path, "path");
  786. File pathParent = path.getParentFile();
  787. if (null == pathParent) {
  788. pathParent = DEFAULT_PARENT;
  789. }
  790. if (!pathParent.canWrite()) {
  791. pathParent.mkdirs();
  792. }
  793. throwIaxUnlessCanWriteDir(pathParent, "pathParent");
  794. return pathParent;
  795. }
  796. /**
  797. * Copy file to file.
  798. *
  799. * @param fromFile the File to copy (readable, non-null file)
  800. * @param toFile the File to copy to (non-null, parent dir exists)
  801. * @throws IOException
  802. */
  803. public static void copyValidFiles(File fromFile, File toFile) throws IOException {
  804. FileInputStream in = null;
  805. FileOutputStream out = null;
  806. try {
  807. in = new FileInputStream(fromFile);
  808. out = new FileOutputStream(toFile);
  809. copyStream(in, out);
  810. } finally {
  811. if (out != null) {
  812. out.close();
  813. }
  814. if (in != null) {
  815. in.close();
  816. }
  817. }
  818. }
  819. /** do line-based copying */
  820. @SuppressWarnings("deprecation")
  821. public static void copyStream(DataInputStream in, PrintStream out) throws IOException {
  822. LangUtil.throwIaxIfNull(in, "in");
  823. LangUtil.throwIaxIfNull(in, "out");
  824. String s;
  825. while (null != (s = in.readLine())) {
  826. out.println(s);
  827. }
  828. }
  829. public static void copyStream(InputStream in, OutputStream out) throws IOException {
  830. final int MAX = 4096;
  831. byte[] buf = new byte[MAX];
  832. for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
  833. out.write(buf, 0, bytesRead);
  834. }
  835. }
  836. public static void copyStream(Reader in, Writer out) throws IOException {
  837. final int MAX = 4096;
  838. char[] buf = new char[MAX];
  839. for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
  840. out.write(buf, 0, bytesRead);
  841. }
  842. }
  843. /**
  844. * Make a new child directory of parent
  845. *
  846. * @param parent a File for the parent (writable)
  847. * @param child a prefix for the child directory
  848. * @return a File dir that exists with parentDir as the parent file or null
  849. */
  850. public static File makeNewChildDir(File parent, String child) {
  851. if (null == parent || !parent.canWrite() || !parent.isDirectory()) {
  852. throw new IllegalArgumentException("bad parent: " + parent);
  853. } else if (null == child) {
  854. child = "makeNewChildDir";
  855. } else if (!isValidFileName(child)) {
  856. throw new IllegalArgumentException("bad child: " + child);
  857. }
  858. File result = new File(parent, child);
  859. int safety = 1000;
  860. for (String suffix = FileUtil.randomFileString(); ((0 < --safety) && result.exists()); suffix = FileUtil.randomFileString()) {
  861. result = new File(parent, child + suffix);
  862. }
  863. if (result.exists()) {
  864. System.err.println("exhausted files for child dir in " + parent);
  865. return null;
  866. }
  867. return ((result.mkdirs() && result.exists()) ? result : null);
  868. }
  869. /**
  870. * Make a new temporary directory in the same directory that the system uses for temporary files, or if that files, in the
  871. * current directory.
  872. *
  873. * @param name the preferred (simple) name of the directory - may be null.
  874. * @return File of an existing new temp dir, or null if unable to create
  875. */
  876. public static File getTempDir(String name) {
  877. if (null == name) {
  878. name = "FileUtil_getTempDir";
  879. } else if (!isValidFileName(name)) {
  880. throw new IllegalArgumentException(" invalid: " + name);
  881. }
  882. File result = null;
  883. File tempFile = null;
  884. try {
  885. tempFile = File.createTempFile("ignoreMe", ".txt");
  886. File tempParent = tempFile.getParentFile();
  887. result = makeNewChildDir(tempParent, name);
  888. } catch (IOException t) {
  889. result = makeNewChildDir(new File("."), name);
  890. } finally {
  891. if (null != tempFile) {
  892. tempFile.delete();
  893. }
  894. }
  895. return result;
  896. }
  897. public static URL[] getFileURLs(File[] files) {
  898. if ((null == files) || (0 == files.length)) {
  899. return new URL[0];
  900. }
  901. URL[] result = new URL[files.length]; // XXX dangerous non-copy...
  902. for (int i = 0; i < result.length; i++) {
  903. result[i] = getFileURL(files[i]);
  904. }
  905. return result;
  906. }
  907. /**
  908. * Get URL for a File. This appends "/" for directories. prints errors to System.err
  909. *
  910. * @param file the File to convert to URL (not null)
  911. */
  912. @SuppressWarnings("deprecation")
  913. public static URL getFileURL(File file) {
  914. LangUtil.throwIaxIfNull(file, "file");
  915. URL result = null;
  916. try {
  917. result = file.toURL();// TODO AV - was toURI.toURL that does not
  918. // works on Java 1.3
  919. if (null != result) {
  920. return result;
  921. }
  922. String url = "file:" + file.getAbsolutePath().replace('\\', '/');
  923. result = new URL(url + (file.isDirectory() ? "/" : ""));
  924. } catch (MalformedURLException e) {
  925. String m = "Util.makeURL(\"" + file.getPath() + "\" MUE " + e.getMessage();
  926. System.err.println(m);
  927. }
  928. return result;
  929. }
  930. /**
  931. * Write contents to file, returning null on success or error message otherwise. This tries to make any necessary parent
  932. * directories first.
  933. *
  934. * @param file the File to write (not null)
  935. * @param contents the String to write (use "" if null)
  936. * @return String null on no error, error otherwise
  937. */
  938. public static String writeAsString(File file, String contents) {
  939. LangUtil.throwIaxIfNull(file, "file");
  940. if (null == contents) {
  941. contents = "";
  942. }
  943. Writer out = null;
  944. try {
  945. File parentDir = file.getParentFile();
  946. if (!parentDir.exists() && !parentDir.mkdirs()) {
  947. return "unable to make parent dir for " + file;
  948. }
  949. Reader in = new StringReader(contents);
  950. out = new FileWriter(file);
  951. FileUtil.copyStream(in, out);
  952. return null;
  953. } catch (IOException e) {
  954. return LangUtil.unqualifiedClassName(e) + " writing " + file + ": " + e.getMessage();
  955. } finally {
  956. if (null != out) {
  957. try {
  958. out.close();
  959. } catch (IOException e) {
  960. } // ignored
  961. }
  962. }
  963. }
  964. /**
  965. * Reads a boolean array with our encoding
  966. */
  967. public static boolean[] readBooleanArray(DataInputStream s) throws IOException {
  968. int len = s.readInt();
  969. boolean[] ret = new boolean[len];
  970. for (int i = 0; i < len; i++) {
  971. ret[i] = s.readBoolean();
  972. }
  973. return ret;
  974. }
  975. /**
  976. * Writes a boolean array with our encoding
  977. */
  978. public static void writeBooleanArray(boolean[] a, DataOutputStream s) throws IOException {
  979. int len = a.length;
  980. s.writeInt(len);
  981. for (int i = 0; i < len; i++) {
  982. s.writeBoolean(a[i]);
  983. }
  984. }
  985. /**
  986. * Reads an int array with our encoding
  987. */
  988. public static int[] readIntArray(DataInputStream s) throws IOException {
  989. int len = s.readInt();
  990. int[] ret = new int[len];
  991. for (int i = 0; i < len; i++) {
  992. ret[i] = s.readInt();
  993. }
  994. return ret;
  995. }
  996. /**
  997. * Writes an int array with our encoding
  998. */
  999. public static void writeIntArray(int[] a, DataOutputStream s) throws IOException {
  1000. int len = a.length;
  1001. s.writeInt(len);
  1002. for (int i = 0; i < len; i++) {
  1003. s.writeInt(a[i]);
  1004. }
  1005. }
  1006. /**
  1007. * Reads an int array with our encoding
  1008. */
  1009. public static String[] readStringArray(DataInputStream s) throws IOException {
  1010. int len = s.readInt();
  1011. String[] ret = new String[len];
  1012. for (int i = 0; i < len; i++) {
  1013. ret[i] = s.readUTF();
  1014. }
  1015. return ret;
  1016. }
  1017. /**
  1018. * Writes an int array with our encoding
  1019. */
  1020. public static void writeStringArray(String[] a, DataOutputStream s) throws IOException {
  1021. if (a == null) {
  1022. s.writeInt(0);
  1023. return;
  1024. }
  1025. int len = a.length;
  1026. s.writeInt(len);
  1027. for (int i = 0; i < len; i++) {
  1028. s.writeUTF(a[i]);
  1029. }
  1030. }
  1031. /**
  1032. * Returns the contents of this file as a String
  1033. */
  1034. public static String readAsString(File file) throws IOException {
  1035. BufferedReader r = new BufferedReader(new FileReader(file));
  1036. StringBuffer b = new StringBuffer();
  1037. while (true) {
  1038. int ch = r.read();
  1039. if (ch == -1) {
  1040. break;
  1041. }
  1042. b.append((char) ch);
  1043. }
  1044. r.close();
  1045. return b.toString();
  1046. }
  1047. // /**
  1048. // * Returns the contents of this stream as a String
  1049. // */
  1050. // public static String readAsString(InputStream in) throws IOException {
  1051. // BufferedReader r = new BufferedReader(new InputStreamReader(in));
  1052. // StringBuffer b = new StringBuffer();
  1053. // while (true) {
  1054. // int ch = r.read();
  1055. // if (ch == -1)
  1056. // break;
  1057. // b.append((char) ch);
  1058. // }
  1059. // in.close();
  1060. // r.close();
  1061. // return b.toString();
  1062. // }
  1063. /**
  1064. * Returns the contents of this file as a byte[]
  1065. */
  1066. public static byte[] readAsByteArray(File file) throws IOException {
  1067. FileInputStream in = new FileInputStream(file);
  1068. byte[] ret = FileUtil.readAsByteArray(in);
  1069. in.close();
  1070. return ret;
  1071. }
  1072. /**
  1073. * Reads this input stream and returns contents as a byte[]
  1074. */
  1075. public static byte[] readAsByteArray(InputStream inStream) throws IOException {
  1076. int size = 1024;
  1077. byte[] ba = new byte[size];
  1078. int readSoFar = 0;
  1079. while (true) {
  1080. int nRead = inStream.read(ba, readSoFar, size - readSoFar);
  1081. if (nRead == -1) {
  1082. break;
  1083. }
  1084. readSoFar += nRead;
  1085. if (readSoFar == size) {
  1086. int newSize = size * 2;
  1087. byte[] newBa = new byte[newSize];
  1088. System.arraycopy(ba, 0, newBa, 0, size);
  1089. ba = newBa;
  1090. size = newSize;
  1091. }
  1092. }
  1093. byte[] newBa = new byte[readSoFar];
  1094. System.arraycopy(ba, 0, newBa, 0, readSoFar);
  1095. return newBa;
  1096. }
  1097. final static String FILECHARS = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  1098. /** @return semi-random String of length 6 usable as filename suffix */
  1099. static String randomFileString() {
  1100. final double FILECHARS_length = FILECHARS.length();
  1101. final int LEN = 6;
  1102. final char[] result = new char[LEN];
  1103. int index = (int) (Math.random() * 6d);
  1104. for (int i = 0; i < LEN; i++) {
  1105. if (index >= LEN) {
  1106. index = 0;
  1107. }
  1108. result[index++] = FILECHARS.charAt((int) (Math.random() * FILECHARS_length));
  1109. }
  1110. return new String(result);
  1111. }
  1112. public static InputStream getStreamFromZip(String zipFile, String name) {
  1113. try {
  1114. ZipFile zf = new ZipFile(zipFile);
  1115. try {
  1116. ZipEntry entry = zf.getEntry(name);
  1117. return zf.getInputStream(entry);
  1118. } finally {
  1119. // ??? is it safe not to close this zf.close();
  1120. }
  1121. } catch (IOException ioe) {
  1122. return null;
  1123. }
  1124. }
  1125. //
  1126. // public static void extractJar(String zipFile, String outDir) throws
  1127. // IOException {
  1128. // ZipInputStream zs = new ZipInputStream(new FileInputStream(zipFile));
  1129. // ZipEntry entry;
  1130. // while ((entry = zs.getNextEntry()) != null) {
  1131. // if (entry.isDirectory())
  1132. // continue;
  1133. // byte[] in = readAsByteArray(zs);
  1134. //
  1135. // File outFile = new File(outDir + "/" + entry.getName());
  1136. // // if (!outFile.getParentFile().exists())
  1137. // // System.err.println("parent: " + outFile.getParentFile());
  1138. // // System.err.println("parent: " + outFile.getParentFile());
  1139. // outFile.getParentFile().mkdirs();
  1140. // FileOutputStream os = new FileOutputStream(outFile);
  1141. // os.write(in);
  1142. // os.close();
  1143. // zs.closeEntry();
  1144. // }
  1145. // zs.close();
  1146. // }
  1147. /**
  1148. * Do line-based search for literal text in source files, returning file:line where found.
  1149. *
  1150. * @param sought the String text to seek in the file
  1151. * @param sources the List of String paths to the source files
  1152. * @param listAll if false, only list first match in file
  1153. * @param errorSink the PrintStream to print any errors to (one per line) (use null to silently ignore errors)
  1154. * @return List of String of the form file:line for each found entry (never null, might be empty)
  1155. */
  1156. // OPTIMIZE only used by tests? move it out
  1157. public static List<String> lineSeek(String sought, List<String> sources, boolean listAll, PrintStream errorSink) {
  1158. if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sources)) {
  1159. return Collections.emptyList();
  1160. }
  1161. ArrayList<String> result = new ArrayList<String>();
  1162. for (Iterator<String> iter = sources.iterator(); iter.hasNext();) {
  1163. String path = iter.next();
  1164. String error = lineSeek(sought, path, listAll, result);
  1165. if ((null != error) && (null != errorSink)) {
  1166. errorSink.println(error);
  1167. }
  1168. }
  1169. return result;
  1170. }
  1171. /**
  1172. * Do line-based search for literal text in source file, returning line where found as a String in the form
  1173. * {sourcePath}:line:column submitted to the collecting parameter sink. Any error is rendered to String and returned as the
  1174. * result.
  1175. *
  1176. * @param sought the String text to seek in the file
  1177. * @param sources the List of String paths to the source files
  1178. * @param listAll if false, only list first match in file
  1179. * @param List sink the List for String entries of the form {sourcePath}:line:column
  1180. * @return String error if any, or add String entries to sink
  1181. */
  1182. public static String lineSeek(String sought, String sourcePath, boolean listAll, ArrayList<String> sink) {
  1183. if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sourcePath)) {
  1184. return "nothing sought";
  1185. }
  1186. if (LangUtil.isEmpty(sourcePath)) {
  1187. return "no sourcePath";
  1188. }
  1189. final File file = new File(sourcePath);
  1190. if (!file.canRead() || !file.isFile()) {
  1191. return "sourcePath not a readable file";
  1192. }
  1193. int lineNum = 0;
  1194. FileReader fin = null;
  1195. try {
  1196. fin = new FileReader(file);
  1197. BufferedReader reader = new BufferedReader(fin);
  1198. String line;
  1199. while (null != (line = reader.readLine())) {
  1200. lineNum++;
  1201. int loc = line.indexOf(sought);
  1202. if (-1 != loc) {
  1203. sink.add(sourcePath + ":" + lineNum + ":" + loc);
  1204. if (!listAll) {
  1205. break;
  1206. }
  1207. }
  1208. }
  1209. } catch (IOException e) {
  1210. return LangUtil.unqualifiedClassName(e) + " reading " + sourcePath + ":" + lineNum;
  1211. } finally {
  1212. try {
  1213. if (null != fin) {
  1214. fin.close();
  1215. }
  1216. } catch (IOException e) {
  1217. } // ignore
  1218. }
  1219. return null;
  1220. }
  1221. public static BufferedOutputStream makeOutputStream(File file) throws FileNotFoundException {
  1222. File parent = file.getParentFile();
  1223. if (parent != null) {
  1224. parent.mkdirs();
  1225. }
  1226. return new BufferedOutputStream(new FileOutputStream(file));
  1227. }
  1228. /**
  1229. * Sleep until after the last last-modified stamp from the files.
  1230. *
  1231. * @param files the File[] of files to inspect for last modified times (this ignores null or empty files array and null or
  1232. * non-existing components of files array)
  1233. * @return true if succeeded without 100 interrupts
  1234. */
  1235. public static boolean sleepPastFinalModifiedTime(File[] files) {
  1236. if ((null == files) || (0 == files.length)) {
  1237. return true;
  1238. }
  1239. long delayUntil = System.currentTimeMillis();
  1240. for (int i = 0; i < files.length; i++) {
  1241. File file = files[i];
  1242. if ((null == file) || !file.exists()) {
  1243. continue;
  1244. }
  1245. long nextModTime = file.lastModified();
  1246. if (nextModTime > delayUntil) {
  1247. delayUntil = nextModTime;
  1248. }
  1249. }
  1250. return LangUtil.sleepUntil(++delayUntil);
  1251. }
  1252. private static void listClassFiles(final File baseDir, ArrayList<File> result) {
  1253. File[] files = baseDir.listFiles();
  1254. for (int i = 0; i < files.length; i++) {
  1255. File f = files[i];
  1256. if (f.isDirectory()) {
  1257. listClassFiles(f, result);
  1258. } else {
  1259. if (f.getName().endsWith(".class")) {
  1260. result.add(f);
  1261. }
  1262. }
  1263. }
  1264. }
  1265. private static void listFiles(final File baseDir, ArrayList<File> result, FileFilter filter) {
  1266. File[] files = baseDir.listFiles();
  1267. // hack https://bugs.eclipse.org/bugs/show_bug.cgi?id=48650
  1268. final boolean skipCVS = (!PERMIT_CVS && (filter == aspectjSourceFileFilter));
  1269. for (int i = 0; i < files.length; i++) {
  1270. File f = files[i];
  1271. if (f.isDirectory()) {
  1272. if (skipCVS) {
  1273. String name = f.getName().toLowerCase();
  1274. if ("cvs".equals(name) || "sccs".equals(name)) {
  1275. continue;
  1276. }
  1277. }
  1278. listFiles(f, result, filter);
  1279. } else {
  1280. if (filter.accept(f)) {
  1281. result.add(f);
  1282. }
  1283. }
  1284. }
  1285. }
  1286. /** @return true if input is not null and contains no path separator */
  1287. private static boolean isValidFileName(String input) {
  1288. return ((null != input) && (-1 == input.indexOf(File.pathSeparator)));
  1289. }
  1290. private static void listFiles(final File baseDir, String dir, ArrayList<String> result) {
  1291. final String dirPrefix = (null == dir ? "" : dir + "/");
  1292. final File dirFile = (null == dir ? baseDir : new File(baseDir.getPath() + "/" + dir));
  1293. final String[] files = dirFile.list();
  1294. for (int i = 0; i < files.length; i++) {
  1295. File f = new File(dirFile, files[i]);
  1296. String path = dirPrefix + files[i];
  1297. if (f.isDirectory()) {
  1298. listFiles(baseDir, path, result);
  1299. } else {
  1300. result.add(path);
  1301. }
  1302. }
  1303. }
  1304. private FileUtil() {
  1305. }
  1306. public static List<String> makeClasspath(URL[] urls) {
  1307. List<String> ret = new LinkedList<String>();
  1308. if (urls != null) {
  1309. for (int i = 0; i < urls.length; i++) {
  1310. ret.add(toPathString(urls[i]));
  1311. }
  1312. }
  1313. return ret;
  1314. }
  1315. private static String toPathString(URL url) {
  1316. try {
  1317. return url.toURI().getPath();
  1318. } catch (URISyntaxException e) {
  1319. System.err.println("Warning!! Malformed URL may cause problems: "+url); // TODO: Better way to report this?
  1320. // In this case it was likely not using properly escaped
  1321. // characters so we just use the 'bad' method that doesn't decode
  1322. // special chars
  1323. return url.getPath();
  1324. }
  1325. }
  1326. /**
  1327. * A pipe when run reads from an input stream to an output stream, optionally sleeping between reads.
  1328. *
  1329. * @see #copyStream(InputStream, OutputStream)
  1330. */
  1331. public static class Pipe implements Runnable {
  1332. private final InputStream in;
  1333. private final OutputStream out;
  1334. private final long sleep;
  1335. private ByteArrayOutputStream snoop;
  1336. private long totalWritten;
  1337. private Throwable thrown;
  1338. private boolean halt;
  1339. /**
  1340. * Seem to be unable to detect erroroneous closing of System.out...
  1341. */
  1342. private final boolean closeInput;
  1343. private final boolean closeOutput;
  1344. /**
  1345. * If true, then continue processing stream until no characters are returned when halting.
  1346. */
  1347. private boolean finishStream;
  1348. private boolean done; // true after completing() completes
  1349. /**
  1350. * alias for <code>Pipe(in, out, 100l, false, false)</code>
  1351. *
  1352. * @param in the InputStream source to read
  1353. * @param out the OutputStream sink to write
  1354. */
  1355. Pipe(InputStream in, OutputStream out) {
  1356. this(in, out, 100l, false, false);
  1357. }
  1358. /**
  1359. * @param in the InputStream source to read
  1360. * @param out the OutputStream sink to write
  1361. * @param tryClosingStreams if true, then try closing both streams when done
  1362. * @param sleep milliseconds to delay between reads (pinned to 0..1 minute)
  1363. */
  1364. Pipe(InputStream in, OutputStream out, long sleep, boolean closeInput, boolean closeOutput) {
  1365. LangUtil.throwIaxIfNull(in, "in");
  1366. LangUtil.throwIaxIfNull(out, "out");
  1367. this.in = in;
  1368. this.out = out;
  1369. this.closeInput = closeInput;
  1370. this.closeOutput = closeOutput;
  1371. this.sleep = Math.min(0l, Math.max(60l * 1000l, sleep));
  1372. }
  1373. public void setSnoop(ByteArrayOutputStream snoop) {
  1374. this.snoop = snoop;
  1375. }
  1376. /**
  1377. * Run the pipe. This halts on the first Throwable thrown or when a read returns -1 (for end-of-file) or on demand.
  1378. */
  1379. public void run() {
  1380. totalWritten = 0;
  1381. if (halt) {
  1382. return;
  1383. }
  1384. try {
  1385. final int MAX = 4096;
  1386. byte[] buf = new byte[MAX];
  1387. // TODO this blocks, hanging the harness
  1388. int count = in.read(buf, 0, MAX);
  1389. ByteArrayOutputStream mySnoop;
  1390. while ((halt && finishStream && (0 < count)) || (!halt && (-1 != count))) {
  1391. out.write(buf, 0, count);
  1392. mySnoop = snoop;
  1393. if (null != mySnoop) {
  1394. mySnoop.write(buf, 0, count);
  1395. }
  1396. totalWritten += count;
  1397. if (halt && !finishStream) {
  1398. break;
  1399. }
  1400. if (!halt && (0 < sleep)) {
  1401. Thread.sleep(sleep);
  1402. }
  1403. if (halt && !finishStream) {
  1404. break;
  1405. }
  1406. count = in.read(buf, 0, MAX);
  1407. }
  1408. } catch (Throwable e) {
  1409. thrown = e;
  1410. } finally {
  1411. halt = true;
  1412. if (closeInput) {
  1413. try {
  1414. in.close();
  1415. } catch (IOException e) {
  1416. // ignore
  1417. }
  1418. }
  1419. if (closeOutput) {
  1420. try {
  1421. out.close();
  1422. } catch (IOException e) {
  1423. // ignore
  1424. }
  1425. }
  1426. done = true;
  1427. completing(totalWritten, thrown);
  1428. }
  1429. }
  1430. /**
  1431. * Tell the pipe to halt the next time it gains control.
  1432. *
  1433. * @param wait if true, this waits synchronously until pipe is done
  1434. * @param finishStream if true, then continue until a read from the input stream returns no bytes, then halt.
  1435. * @return true if <code>run()</code> will return the next time it gains control
  1436. */
  1437. public boolean halt(boolean wait, boolean finishStream) {
  1438. if (!halt) {
  1439. halt = true;
  1440. }
  1441. if (wait) {
  1442. while (!done) {
  1443. synchronized (this) {
  1444. notifyAll();
  1445. }
  1446. if (!done) {
  1447. try {
  1448. Thread.sleep(5l);
  1449. } catch (InterruptedException e) {
  1450. break;
  1451. }
  1452. }
  1453. }
  1454. }
  1455. return halt;
  1456. }
  1457. /** @return the total number of bytes written */
  1458. public long totalWritten() {
  1459. return totalWritten;
  1460. }
  1461. /** @return any exception thrown when reading/writing */
  1462. public Throwable getThrown() {
  1463. return thrown;
  1464. }
  1465. /**
  1466. * This is called when the pipe is completing. This implementation does nothing. Subclasses implement this to get notice.
  1467. * Note that halt(true, true) might or might not have completed before this method is called.
  1468. */
  1469. protected void completing(long totalWritten, Throwable thrown) {
  1470. }
  1471. }
  1472. }