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

ExecuteOn.java 28 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package org.apache.tools.ant.taskdefs;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.util.Hashtable;
  22. import java.util.Iterator;
  23. import java.util.Vector;
  24. import org.apache.tools.ant.BuildException;
  25. import org.apache.tools.ant.DirectoryScanner;
  26. import org.apache.tools.ant.Project;
  27. import org.apache.tools.ant.types.Commandline;
  28. import org.apache.tools.ant.types.AbstractFileSet;
  29. import org.apache.tools.ant.types.DirSet;
  30. import org.apache.tools.ant.types.EnumeratedAttribute;
  31. import org.apache.tools.ant.types.FileList;
  32. import org.apache.tools.ant.types.FileSet;
  33. import org.apache.tools.ant.types.Mapper;
  34. import org.apache.tools.ant.types.Resource;
  35. import org.apache.tools.ant.types.ResourceCollection;
  36. import org.apache.tools.ant.types.resources.FileProvider;
  37. import org.apache.tools.ant.types.resources.FileResource;
  38. import org.apache.tools.ant.types.resources.Union;
  39. import org.apache.tools.ant.util.FileNameMapper;
  40. import org.apache.tools.ant.util.ResourceUtils;
  41. import org.apache.tools.ant.util.SourceFileScanner;
  42. /**
  43. * Executes a given command, supplying a set of files as arguments.
  44. *
  45. * @since Ant 1.2
  46. *
  47. * @ant.task category="control" name="apply"
  48. */
  49. public class ExecuteOn extends ExecTask {
  50. // CheckStyle:VisibilityModifier OFF - bc
  51. // filesets has been protected so we need to keep that even after
  52. // switching to resource collections. In fact, they will still
  53. // get a different treatment form the other resource collections
  54. // even in execute since we have some subtle special features like
  55. // switching type to "dir" when we encounter a DirSet that would
  56. // be more difficult to achieve otherwise.
  57. protected Vector filesets = new Vector(); // contains AbstractFileSet
  58. // (both DirSet and FileSet)
  59. private Union resources = null;
  60. private boolean relative = false;
  61. private boolean parallel = false;
  62. private boolean forwardSlash = false;
  63. protected String type = FileDirBoth.FILE;
  64. protected Commandline.Marker srcFilePos = null;
  65. private boolean skipEmpty = false;
  66. protected Commandline.Marker targetFilePos = null;
  67. protected Mapper mapperElement = null;
  68. protected FileNameMapper mapper = null;
  69. protected File destDir = null;
  70. private int maxParallel = -1;
  71. private boolean addSourceFile = true;
  72. private boolean verbose = false;
  73. private boolean ignoreMissing = true;
  74. private boolean force = false;
  75. /**
  76. * Has <srcfile> been specified before <targetfile>
  77. */
  78. protected boolean srcIsFirst = true;
  79. // CheckStyle:VisibilityModifier ON
  80. /**
  81. * Add a set of files upon which to operate.
  82. * @param set the FileSet to add.
  83. */
  84. public void addFileset(FileSet set) {
  85. filesets.addElement(set);
  86. }
  87. /**
  88. * Add a set of directories upon which to operate.
  89. *
  90. * @param set the DirSet to add.
  91. *
  92. * @since Ant 1.6
  93. */
  94. public void addDirset(DirSet set) {
  95. filesets.addElement(set);
  96. }
  97. /**
  98. * Add a list of source files upon which to operate.
  99. * @param list the FileList to add.
  100. */
  101. public void addFilelist(FileList list) {
  102. add(list);
  103. }
  104. /**
  105. * Add a collection of resources upon which to operate.
  106. * @param rc resource collection to add.
  107. * @since Ant 1.7
  108. */
  109. public void add(ResourceCollection rc) {
  110. if (resources == null) {
  111. resources = new Union();
  112. }
  113. resources.add(rc);
  114. }
  115. /**
  116. * Set whether the filenames should be passed on the command line as
  117. * absolute or relative pathnames. Paths are relative to the base
  118. * directory of the corresponding fileset for source files or the
  119. * dest attribute for target files.
  120. * @param relative whether to pass relative pathnames.
  121. */
  122. public void setRelative(boolean relative) {
  123. this.relative = relative;
  124. }
  125. /**
  126. * Set whether to execute in parallel mode.
  127. * If true, run the command only once, appending all files as arguments.
  128. * If false, command will be executed once for every file. Defaults to false.
  129. * @param parallel whether to run in parallel.
  130. */
  131. public void setParallel(boolean parallel) {
  132. this.parallel = parallel;
  133. }
  134. /**
  135. * Set whether the command works only on files, directories or both.
  136. * @param type a FileDirBoth EnumeratedAttribute.
  137. */
  138. public void setType(FileDirBoth type) {
  139. this.type = type.getValue();
  140. }
  141. /**
  142. * Set whether empty filesets will be skipped. If true and
  143. * no source files have been found or are newer than their
  144. * corresponding target files, the command will not be run.
  145. * @param skip whether to skip empty filesets.
  146. */
  147. public void setSkipEmptyFilesets(boolean skip) {
  148. skipEmpty = skip;
  149. }
  150. /**
  151. * Specify the directory where target files are to be placed.
  152. * @param destDir the File object representing the destination directory.
  153. */
  154. public void setDest(File destDir) {
  155. this.destDir = destDir;
  156. }
  157. /**
  158. * Set whether the source and target file names on Windows and OS/2
  159. * must use the forward slash as file separator.
  160. * @param forwardSlash whether the forward slash will be forced.
  161. */
  162. public void setForwardslash(boolean forwardSlash) {
  163. this.forwardSlash = forwardSlash;
  164. }
  165. /**
  166. * Limit the command line length by passing at maximum this many
  167. * sourcefiles at once to the command.
  168. *
  169. * <p>Set to &lt;= 0 for unlimited - this is the default.</p>
  170. *
  171. * @param max <code>int</code> maximum number of sourcefiles
  172. * passed to the executable.
  173. *
  174. * @since Ant 1.6
  175. */
  176. public void setMaxParallel(int max) {
  177. maxParallel = max;
  178. }
  179. /**
  180. * Set whether to send the source file name on the command line.
  181. *
  182. * <p>Defaults to <code>true</code>.
  183. *
  184. * @param b whether to add the source file to the command line.
  185. *
  186. * @since Ant 1.6
  187. */
  188. public void setAddsourcefile(boolean b) {
  189. addSourceFile = b;
  190. }
  191. /**
  192. * Set whether to operate in verbose mode.
  193. * If true, a verbose summary will be printed after execution.
  194. * @param b whether to operate in verbose mode.
  195. *
  196. * @since Ant 1.6
  197. */
  198. public void setVerbose(boolean b) {
  199. verbose = b;
  200. }
  201. /**
  202. * Set whether to ignore nonexistent files from filelists.
  203. * @param b whether to ignore missing files.
  204. *
  205. * @since Ant 1.6.2
  206. */
  207. public void setIgnoremissing(boolean b) {
  208. ignoreMissing = b;
  209. }
  210. /**
  211. * Set whether to bypass timestamp comparisons for target files.
  212. * @param b whether to bypass timestamp comparisons.
  213. *
  214. * @since Ant 1.6.3
  215. */
  216. public void setForce(boolean b) {
  217. force = b;
  218. }
  219. /**
  220. * Create a placeholder indicating where on the command line
  221. * the name of the source file should be inserted.
  222. * @return <code>Commandline.Marker</code>.
  223. */
  224. public Commandline.Marker createSrcfile() {
  225. if (srcFilePos != null) {
  226. throw new BuildException(getTaskType() + " doesn\'t support multiple "
  227. + "srcfile elements.", getLocation());
  228. }
  229. srcFilePos = cmdl.createMarker();
  230. return srcFilePos;
  231. }
  232. /**
  233. * Create a placeholder indicating where on the command line
  234. * the name of the target file should be inserted.
  235. * @return <code>Commandline.Marker</code>.
  236. */
  237. public Commandline.Marker createTargetfile() {
  238. if (targetFilePos != null) {
  239. throw new BuildException(getTaskType() + " doesn\'t support multiple "
  240. + "targetfile elements.", getLocation());
  241. }
  242. targetFilePos = cmdl.createMarker();
  243. srcIsFirst = (srcFilePos != null);
  244. return targetFilePos;
  245. }
  246. /**
  247. * Create a nested Mapper element to use for mapping
  248. * source files to target files.
  249. * @return <code>Mapper</code>.
  250. * @throws BuildException if more than one mapper is defined.
  251. */
  252. public Mapper createMapper() throws BuildException {
  253. if (mapperElement != null) {
  254. throw new BuildException("Cannot define more than one mapper",
  255. getLocation());
  256. }
  257. mapperElement = new Mapper(getProject());
  258. return mapperElement;
  259. }
  260. /**
  261. * Add a nested FileNameMapper.
  262. * @param fileNameMapper the mapper to add.
  263. * @since Ant 1.6.3
  264. */
  265. public void add(FileNameMapper fileNameMapper) {
  266. createMapper().add(fileNameMapper);
  267. }
  268. /**
  269. * Check the configuration of this ExecuteOn instance.
  270. */
  271. protected void checkConfiguration() {
  272. // * @TODO using taskName here is brittle, as a user could override it.
  273. // * this should probably be modified to use the classname instead.
  274. if ("execon".equals(getTaskName())) {
  275. log("!! execon is deprecated. Use apply instead. !!");
  276. }
  277. super.checkConfiguration();
  278. if (filesets.size() == 0 && resources == null) {
  279. throw new BuildException("no resources specified",
  280. getLocation());
  281. }
  282. if (targetFilePos != null && mapperElement == null) {
  283. throw new BuildException("targetfile specified without mapper",
  284. getLocation());
  285. }
  286. if (destDir != null && mapperElement == null) {
  287. throw new BuildException("dest specified without mapper",
  288. getLocation());
  289. }
  290. if (mapperElement != null) {
  291. mapper = mapperElement.getImplementation();
  292. }
  293. }
  294. /**
  295. * Create the ExecuteStreamHandler instance that will be used
  296. * during execution.
  297. * @return <code>ExecuteStreamHandler</code>.
  298. * @throws BuildException on error.
  299. */
  300. protected ExecuteStreamHandler createHandler() throws BuildException {
  301. //if we have a RedirectorElement, return a decoy
  302. return (redirectorElement == null)
  303. ? super.createHandler() : new PumpStreamHandler();
  304. }
  305. /**
  306. * Set up the I/O Redirector.
  307. */
  308. protected void setupRedirector() {
  309. super.setupRedirector();
  310. redirector.setAppendProperties(true);
  311. }
  312. /**
  313. * Run the specified Execute object.
  314. * @param exe the Execute instance representing the external process.
  315. * @throws BuildException on error
  316. */
  317. protected void runExec(Execute exe) throws BuildException {
  318. int totalFiles = 0;
  319. int totalDirs = 0;
  320. boolean haveExecuted = false;
  321. try {
  322. Vector fileNames = new Vector();
  323. Vector baseDirs = new Vector();
  324. for (int i = 0; i < filesets.size(); i++) {
  325. String currentType = type;
  326. AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i);
  327. if (fs instanceof DirSet) {
  328. if (!FileDirBoth.DIR.equals(type)) {
  329. log("Found a nested dirset but type is " + type + ". "
  330. + "Temporarily switching to type=\"dir\" on the"
  331. + " assumption that you really did mean"
  332. + " <dirset> not <fileset>.", Project.MSG_DEBUG);
  333. currentType = FileDirBoth.DIR;
  334. }
  335. }
  336. File base = fs.getDir(getProject());
  337. DirectoryScanner ds = fs.getDirectoryScanner(getProject());
  338. if (!FileDirBoth.DIR.equals(currentType)) {
  339. String[] s = getFiles(base, ds);
  340. for (int j = 0; j < s.length; j++) {
  341. totalFiles++;
  342. fileNames.addElement(s[j]);
  343. baseDirs.addElement(base);
  344. }
  345. }
  346. if (!FileDirBoth.FILE.equals(currentType)) {
  347. String[] s = getDirs(base, ds);
  348. for (int j = 0; j < s.length; j++) {
  349. totalDirs++;
  350. fileNames.addElement(s[j]);
  351. baseDirs.addElement(base);
  352. }
  353. }
  354. if (fileNames.size() == 0 && skipEmpty) {
  355. logSkippingFileset(currentType, ds, base);
  356. continue;
  357. }
  358. if (!parallel) {
  359. String[] s = new String[fileNames.size()];
  360. fileNames.copyInto(s);
  361. for (int j = 0; j < s.length; j++) {
  362. String[] command = getCommandline(s[j], base);
  363. log(Commandline.describeCommand(command),
  364. Project.MSG_VERBOSE);
  365. exe.setCommandline(command);
  366. if (redirectorElement != null) {
  367. setupRedirector();
  368. redirectorElement.configure(redirector, s[j]);
  369. }
  370. if (redirectorElement != null || haveExecuted) {
  371. // need to reset the stream handler to restart
  372. // reading of pipes;
  373. // go ahead and do it always w/ nested redirectors
  374. exe.setStreamHandler(redirector.createHandler());
  375. }
  376. runExecute(exe);
  377. haveExecuted = true;
  378. }
  379. fileNames.removeAllElements();
  380. baseDirs.removeAllElements();
  381. }
  382. }
  383. if (resources != null) {
  384. Iterator iter = resources.iterator();
  385. while (iter.hasNext()) {
  386. Resource res = (Resource) iter.next();
  387. if (!res.isExists() && ignoreMissing) {
  388. continue;
  389. }
  390. File base = null;
  391. String name = res.getName();
  392. if (res instanceof FileProvider) {
  393. FileResource fr = ResourceUtils.asFileResource((FileProvider) res);
  394. base = fr.getBaseDir();
  395. if (base == null) {
  396. name = fr.getFile().getAbsolutePath();
  397. }
  398. }
  399. if (restrict(new String[] {name}, base).length == 0) {
  400. continue;
  401. }
  402. if ((!res.isDirectory() || !res.isExists())
  403. && !FileDirBoth.DIR.equals(type)) {
  404. totalFiles++;
  405. } else if (res.isDirectory()
  406. && !FileDirBoth.FILE.equals(type)) {
  407. totalDirs++;
  408. } else {
  409. continue;
  410. }
  411. baseDirs.add(base);
  412. fileNames.add(name);
  413. if (!parallel) {
  414. String[] command = getCommandline(name, base);
  415. log(Commandline.describeCommand(command),
  416. Project.MSG_VERBOSE);
  417. exe.setCommandline(command);
  418. if (redirectorElement != null) {
  419. setupRedirector();
  420. redirectorElement.configure(redirector, name);
  421. }
  422. if (redirectorElement != null || haveExecuted) {
  423. // need to reset the stream handler to restart
  424. // reading of pipes;
  425. // go ahead and do it always w/ nested redirectors
  426. exe.setStreamHandler(redirector.createHandler());
  427. }
  428. runExecute(exe);
  429. haveExecuted = true;
  430. fileNames.removeAllElements();
  431. baseDirs.removeAllElements();
  432. }
  433. }
  434. }
  435. if (parallel && (fileNames.size() > 0 || !skipEmpty)) {
  436. runParallel(exe, fileNames, baseDirs);
  437. haveExecuted = true;
  438. }
  439. if (haveExecuted) {
  440. log("Applied " + cmdl.getExecutable() + " to "
  441. + totalFiles + " file"
  442. + (totalFiles != 1 ? "s" : "") + " and "
  443. + totalDirs + " director"
  444. + (totalDirs != 1 ? "ies" : "y") + ".",
  445. verbose ? Project.MSG_INFO : Project.MSG_VERBOSE);
  446. }
  447. } catch (IOException e) {
  448. throw new BuildException("Execute failed: " + e, e, getLocation());
  449. } finally {
  450. // close the output file if required
  451. logFlush();
  452. redirector.setAppendProperties(false);
  453. redirector.setProperties();
  454. }
  455. }
  456. /**
  457. * log a message for skipping a fileset.
  458. * @param currentType the current type.
  459. * @param ds the directory scanner.
  460. * @param base the dir base
  461. */
  462. private void logSkippingFileset(
  463. String currentType, DirectoryScanner ds, File base) {
  464. int includedCount
  465. = ((!FileDirBoth.DIR.equals(currentType))
  466. ? ds.getIncludedFilesCount() : 0)
  467. + ((!FileDirBoth.FILE.equals(currentType))
  468. ? ds.getIncludedDirsCount() : 0);
  469. log("Skipping fileset for directory " + base + ". It is "
  470. + ((includedCount > 0) ? "up to date." : "empty."),
  471. verbose ? Project.MSG_INFO : Project.MSG_VERBOSE);
  472. }
  473. /**
  474. * Construct the command line for parallel execution.
  475. *
  476. * @param srcFiles The filenames to add to the commandline.
  477. * @param baseDirs filenames are relative to this dir.
  478. * @return the command line in the form of a String[].
  479. */
  480. protected String[] getCommandline(String[] srcFiles, File[] baseDirs) {
  481. final char fileSeparator = File.separatorChar;
  482. Vector targets = new Vector();
  483. if (targetFilePos != null) {
  484. Hashtable addedFiles = new Hashtable();
  485. for (int i = 0; i < srcFiles.length; i++) {
  486. String[] subTargets = mapper.mapFileName(srcFiles[i]);
  487. if (subTargets != null) {
  488. for (int j = 0; j < subTargets.length; j++) {
  489. String name = null;
  490. if (!relative) {
  491. name = (new File(destDir, subTargets[j])).getAbsolutePath();
  492. } else {
  493. name = subTargets[j];
  494. }
  495. if (forwardSlash && fileSeparator != '/') {
  496. name = name.replace(fileSeparator, '/');
  497. }
  498. if (!addedFiles.contains(name)) {
  499. targets.addElement(name);
  500. addedFiles.put(name, name);
  501. }
  502. }
  503. }
  504. }
  505. }
  506. String[] targetFiles = (String[]) targets.toArray(new String[targets.size()]);
  507. if (!addSourceFile) {
  508. srcFiles = new String[0];
  509. }
  510. String[] orig = cmdl.getCommandline();
  511. String[] result
  512. = new String[orig.length + srcFiles.length + targetFiles.length];
  513. int srcIndex = orig.length;
  514. if (srcFilePos != null) {
  515. srcIndex = srcFilePos.getPosition();
  516. }
  517. if (targetFilePos != null) {
  518. int targetIndex = targetFilePos.getPosition();
  519. if (srcIndex < targetIndex
  520. || (srcIndex == targetIndex && srcIsFirst)) {
  521. // 0 --> srcIndex
  522. System.arraycopy(orig, 0, result, 0, srcIndex);
  523. // srcIndex --> targetIndex
  524. System.arraycopy(orig, srcIndex, result,
  525. srcIndex + srcFiles.length,
  526. targetIndex - srcIndex);
  527. // targets are already absolute file names
  528. System.arraycopy(targetFiles, 0, result,
  529. targetIndex + srcFiles.length,
  530. targetFiles.length);
  531. // targetIndex --> end
  532. System.arraycopy(orig, targetIndex, result,
  533. targetIndex + srcFiles.length + targetFiles.length,
  534. orig.length - targetIndex);
  535. } else {
  536. // 0 --> targetIndex
  537. System.arraycopy(orig, 0, result, 0, targetIndex);
  538. // targets are already absolute file names
  539. System.arraycopy(targetFiles, 0, result,
  540. targetIndex,
  541. targetFiles.length);
  542. // targetIndex --> srcIndex
  543. System.arraycopy(orig, targetIndex, result,
  544. targetIndex + targetFiles.length,
  545. srcIndex - targetIndex);
  546. // srcIndex --> end
  547. System.arraycopy(orig, srcIndex, result,
  548. srcIndex + srcFiles.length + targetFiles.length,
  549. orig.length - srcIndex);
  550. srcIndex += targetFiles.length;
  551. }
  552. } else { // no targetFilePos
  553. // 0 --> srcIndex
  554. System.arraycopy(orig, 0, result, 0, srcIndex);
  555. // srcIndex --> end
  556. System.arraycopy(orig, srcIndex, result,
  557. srcIndex + srcFiles.length,
  558. orig.length - srcIndex);
  559. }
  560. // fill in source file names
  561. for (int i = 0; i < srcFiles.length; i++) {
  562. String src;
  563. if (relative) {
  564. src = srcFiles[i];
  565. } else {
  566. src = new File(baseDirs[i], srcFiles[i]).getAbsolutePath();
  567. }
  568. if (forwardSlash && fileSeparator != '/') {
  569. src = src.replace(fileSeparator, '/');
  570. }
  571. result[srcIndex + i] = src;
  572. }
  573. return result;
  574. }
  575. /**
  576. * Construct the command line for serial execution.
  577. *
  578. * @param srcFile The filename to add to the commandline.
  579. * @param baseDir filename is relative to this dir.
  580. * @return the command line in the form of a String[].
  581. */
  582. protected String[] getCommandline(String srcFile, File baseDir) {
  583. return getCommandline(new String[] {srcFile}, new File[] {baseDir});
  584. }
  585. /**
  586. * Return the list of files from this DirectoryScanner that should
  587. * be included on the command line.
  588. * @param baseDir the File base directory.
  589. * @param ds the DirectoryScanner to use for file scanning.
  590. * @return a String[] containing the filenames.
  591. */
  592. protected String[] getFiles(File baseDir, DirectoryScanner ds) {
  593. return restrict(ds.getIncludedFiles(), baseDir);
  594. }
  595. /**
  596. * Return the list of Directories from this DirectoryScanner that
  597. * should be included on the command line.
  598. * @param baseDir the File base directory.
  599. * @param ds the DirectoryScanner to use for file scanning.
  600. * @return a String[] containing the directory names.
  601. */
  602. protected String[] getDirs(File baseDir, DirectoryScanner ds) {
  603. return restrict(ds.getIncludedDirectories(), baseDir);
  604. }
  605. /**
  606. * Return the list of files or directories from this FileList that
  607. * should be included on the command line.
  608. * @param list the FileList to check.
  609. * @return a String[] containing the directory names.
  610. *
  611. * @since Ant 1.6.2
  612. */
  613. protected String[] getFilesAndDirs(FileList list) {
  614. return restrict(list.getFiles(getProject()), list.getDir(getProject()));
  615. }
  616. private String[] restrict(String[] s, File baseDir) {
  617. return (mapper == null || force) ? s
  618. : new SourceFileScanner(this).restrict(s, baseDir, destDir, mapper);
  619. }
  620. /**
  621. * Run the command in "parallel" mode, making sure that at most
  622. * maxParallel sourcefiles get passed on the command line.
  623. * @param exe the Executable to use.
  624. * @param fileNames the Vector of filenames.
  625. * @param baseDirs the Vector of base directories corresponding to fileNames.
  626. * @throws IOException on I/O errors.
  627. * @throws BuildException on other errors.
  628. * @since Ant 1.6
  629. */
  630. protected void runParallel(Execute exe, Vector fileNames,
  631. Vector baseDirs)
  632. throws IOException, BuildException {
  633. String[] s = new String[fileNames.size()];
  634. fileNames.copyInto(s);
  635. File[] b = new File[baseDirs.size()];
  636. baseDirs.copyInto(b);
  637. if (maxParallel <= 0
  638. || s.length == 0 /* this is skipEmpty == false */) {
  639. String[] command = getCommandline(s, b);
  640. log(Commandline.describeCommand(command), Project.MSG_VERBOSE);
  641. exe.setCommandline(command);
  642. runExecute(exe);
  643. } else {
  644. int stillToDo = fileNames.size();
  645. int currentOffset = 0;
  646. while (stillToDo > 0) {
  647. int currentAmount = Math.min(stillToDo, maxParallel);
  648. String[] cs = new String[currentAmount];
  649. System.arraycopy(s, currentOffset, cs, 0, currentAmount);
  650. File[] cb = new File[currentAmount];
  651. System.arraycopy(b, currentOffset, cb, 0, currentAmount);
  652. String[] command = getCommandline(cs, cb);
  653. log(Commandline.describeCommand(command), Project.MSG_VERBOSE);
  654. exe.setCommandline(command);
  655. if (redirectorElement != null) {
  656. setupRedirector();
  657. redirectorElement.configure(redirector, null);
  658. }
  659. if (redirectorElement != null || currentOffset > 0) {
  660. // need to reset the stream handler to restart
  661. // reading of pipes;
  662. // go ahead and do it always w/ nested redirectors
  663. exe.setStreamHandler(redirector.createHandler());
  664. }
  665. runExecute(exe);
  666. stillToDo -= currentAmount;
  667. currentOffset += currentAmount;
  668. }
  669. }
  670. }
  671. /**
  672. * Enumerated attribute with the values "file", "dir" and "both"
  673. * for the type attribute.
  674. */
  675. public static class FileDirBoth extends EnumeratedAttribute {
  676. /** File value */
  677. public static final String FILE = "file";
  678. /** Dir value */
  679. public static final String DIR = "dir";
  680. /**
  681. * @see EnumeratedAttribute#getValues
  682. */
  683. /** {@inheritDoc}. */
  684. public String[] getValues() {
  685. return new String[] {FILE, DIR, "both"};
  686. }
  687. }
  688. }