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.

Ant.java 27 kB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  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.io.PrintStream;
  22. import java.lang.reflect.Method;
  23. import java.util.HashMap;
  24. import java.nio.file.Files;
  25. import java.util.HashSet;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.Objects;
  30. import java.util.Set;
  31. import java.util.Vector;
  32. import org.apache.tools.ant.BuildException;
  33. import org.apache.tools.ant.BuildListener;
  34. import org.apache.tools.ant.DefaultLogger;
  35. import org.apache.tools.ant.MagicNames;
  36. import org.apache.tools.ant.Main;
  37. import org.apache.tools.ant.Project;
  38. import org.apache.tools.ant.ProjectComponent;
  39. import org.apache.tools.ant.ProjectHelper;
  40. import org.apache.tools.ant.Target;
  41. import org.apache.tools.ant.Task;
  42. import org.apache.tools.ant.types.PropertySet;
  43. import org.apache.tools.ant.util.FileUtils;
  44. import org.apache.tools.ant.util.VectorSet;
  45. /**
  46. * Build a sub-project.
  47. *
  48. * <pre>
  49. * &lt;target name=&quot;foo&quot; depends=&quot;init&quot;&gt;
  50. * &lt;ant antfile=&quot;build.xml&quot; target=&quot;bar&quot; &gt;
  51. * &lt;property name=&quot;property1&quot; value=&quot;aaaaa&quot; /&gt;
  52. * &lt;property name=&quot;foo&quot; value=&quot;baz&quot; /&gt;
  53. * &lt;/ant&gt;
  54. * &lt;/target&gt;
  55. *
  56. * &lt;target name=&quot;bar&quot; depends=&quot;init&quot;&gt;
  57. * &lt;echo message=&quot;prop is ${property1} ${foo}&quot; /&gt;
  58. * &lt;/target&gt;
  59. * </pre>
  60. *
  61. *
  62. * @since Ant 1.1
  63. *
  64. * @ant.task category="control"
  65. */
  66. public class Ant extends Task {
  67. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  68. /** the basedir where is executed the build file */
  69. private File dir = null;
  70. /**
  71. * the build.xml file (can be absolute) in this case dir will be
  72. * ignored
  73. */
  74. private String antFile = null;
  75. /** the output */
  76. private String output = null;
  77. /** should we inherit properties from the parent ? */
  78. private boolean inheritAll = true;
  79. /** should we inherit references from the parent ? */
  80. private boolean inheritRefs = false;
  81. /** the properties to pass to the new project */
  82. private List<Property> properties = new Vector<>();
  83. /** the references to pass to the new project */
  84. private List<Reference> references = new Vector<>();
  85. /** the temporary project created to run the build file */
  86. private Project newProject;
  87. /** The stream to which output is to be written. */
  88. private PrintStream out = null;
  89. /** the sets of properties to pass to the new project */
  90. private List<PropertySet> propertySets = new Vector<>();
  91. /** the targets to call on the new project */
  92. private List<String> targets = new Vector<>();
  93. /** whether the target attribute was specified **/
  94. private boolean targetAttributeSet = false;
  95. /**
  96. * Whether the basedir of the new project should be the same one
  97. * as it would be when running the build file directly -
  98. * independent of dir and/or inheritAll settings.
  99. *
  100. * @since Ant 1.8.0
  101. */
  102. private boolean useNativeBasedir = false;
  103. /**
  104. * simple constructor
  105. */
  106. public Ant() {
  107. //default
  108. }
  109. /**
  110. * create a task bound to its creator
  111. * @param owner owning task
  112. */
  113. public Ant(Task owner) {
  114. bindToOwner(owner);
  115. }
  116. /**
  117. * Whether the basedir of the new project should be the same one
  118. * as it would be when running the build file directly -
  119. * independent of dir and/or inheritAll settings.
  120. *
  121. * @param b boolean
  122. * @since Ant 1.8.0
  123. */
  124. public void setUseNativeBasedir(boolean b) {
  125. useNativeBasedir = b;
  126. }
  127. /**
  128. * If true, pass all properties to the new Ant project.
  129. * Defaults to true.
  130. * @param value if true pass all properties to the new Ant project.
  131. */
  132. public void setInheritAll(boolean value) {
  133. inheritAll = value;
  134. }
  135. /**
  136. * If true, pass all references to the new Ant project.
  137. * Defaults to false.
  138. * @param value if true, pass all references to the new Ant project
  139. */
  140. public void setInheritRefs(boolean value) {
  141. inheritRefs = value;
  142. }
  143. /**
  144. * Creates a Project instance for the project to call.
  145. */
  146. @Override
  147. public void init() {
  148. newProject = getProject().createSubProject();
  149. newProject.setJavaVersionProperty();
  150. }
  151. /**
  152. * Called in execute or createProperty (via getNewProject())
  153. * if newProject is null.
  154. *
  155. * <p>This can happen if the same instance of this task is run
  156. * twice as newProject is set to null at the end of execute (to
  157. * save memory and help the GC).</p>
  158. * <p>calls init() again</p>
  159. *
  160. */
  161. private void reinit() {
  162. init();
  163. }
  164. /**
  165. * Attaches the build listeners of the current project to the new
  166. * project, configures a possible logfile, transfers task and
  167. * data-type definitions, transfers properties (either all or just
  168. * the ones specified as user properties to the current project,
  169. * depending on inheritall), transfers the input handler.
  170. */
  171. private void initializeProject() {
  172. newProject.setInputHandler(getProject().getInputHandler());
  173. Iterator<BuildListener> iter = getBuildListeners();
  174. while (iter.hasNext()) {
  175. newProject.addBuildListener(iter.next());
  176. }
  177. if (output != null) {
  178. File outfile;
  179. if (dir != null) {
  180. outfile = FILE_UTILS.resolveFile(dir, output);
  181. } else {
  182. outfile = getProject().resolveFile(output);
  183. }
  184. try {
  185. out = new PrintStream(Files.newOutputStream(outfile.toPath()));
  186. DefaultLogger logger = new DefaultLogger();
  187. logger.setMessageOutputLevel(Project.MSG_INFO);
  188. logger.setOutputPrintStream(out);
  189. logger.setErrorPrintStream(out);
  190. newProject.addBuildListener(logger);
  191. } catch (IOException ex) {
  192. log("Ant: Can't set output to " + output);
  193. }
  194. }
  195. // set user-defined properties
  196. if (useNativeBasedir) {
  197. addAlmostAll(getProject().getUserProperties(), PropertyType.USER);
  198. } else {
  199. getProject().copyUserProperties(newProject);
  200. }
  201. if (!inheritAll) {
  202. // set Ant's built-in properties separately,
  203. // because they are not being inherited.
  204. newProject.initProperties();
  205. } else {
  206. // set all properties from calling project
  207. addAlmostAll(getProject().getProperties(), PropertyType.PLAIN);
  208. }
  209. for (PropertySet ps : propertySets) {
  210. addAlmostAll(ps.getProperties(), PropertyType.PLAIN);
  211. }
  212. }
  213. /**
  214. * Handles output.
  215. * Send it the the new project if is present, otherwise
  216. * call the super class.
  217. * @param outputToHandle The string output to output.
  218. * @see Task#handleOutput(String)
  219. * @since Ant 1.5
  220. */
  221. @Override
  222. public void handleOutput(String outputToHandle) {
  223. if (newProject != null) {
  224. newProject.demuxOutput(outputToHandle, false);
  225. } else {
  226. super.handleOutput(outputToHandle);
  227. }
  228. }
  229. /**
  230. * Handles input.
  231. * Delegate to the created project, if present, otherwise
  232. * call the super class.
  233. * @param buffer the buffer into which data is to be read.
  234. * @param offset the offset into the buffer at which data is stored.
  235. * @param length the amount of data to read.
  236. *
  237. * @return the number of bytes read.
  238. *
  239. * @exception IOException if the data cannot be read.
  240. * @see Task#handleInput(byte[], int, int)
  241. * @since Ant 1.6
  242. */
  243. @Override
  244. public int handleInput(byte[] buffer, int offset, int length)
  245. throws IOException {
  246. if (newProject != null) {
  247. return newProject.demuxInput(buffer, offset, length);
  248. }
  249. return super.handleInput(buffer, offset, length);
  250. }
  251. /**
  252. * Handles output.
  253. * Send it the the new project if is present, otherwise
  254. * call the super class.
  255. * @param toFlush The string to output.
  256. * @see Task#handleFlush(String)
  257. * @since Ant 1.5.2
  258. */
  259. @Override
  260. public void handleFlush(String toFlush) {
  261. if (newProject != null) {
  262. newProject.demuxFlush(toFlush, false);
  263. } else {
  264. super.handleFlush(toFlush);
  265. }
  266. }
  267. /**
  268. * Handle error output.
  269. * Send it the the new project if is present, otherwise
  270. * call the super class.
  271. * @param errorOutputToHandle The string to output.
  272. *
  273. * @see Task#handleErrorOutput(String)
  274. * @since Ant 1.5
  275. */
  276. @Override
  277. public void handleErrorOutput(String errorOutputToHandle) {
  278. if (newProject != null) {
  279. newProject.demuxOutput(errorOutputToHandle, true);
  280. } else {
  281. super.handleErrorOutput(errorOutputToHandle);
  282. }
  283. }
  284. /**
  285. * Handle error output.
  286. * Send it the the new project if is present, otherwise
  287. * call the super class.
  288. * @param errorOutputToFlush The string to output.
  289. * @see Task#handleErrorFlush(String)
  290. * @since Ant 1.5.2
  291. */
  292. @Override
  293. public void handleErrorFlush(String errorOutputToFlush) {
  294. if (newProject != null) {
  295. newProject.demuxFlush(errorOutputToFlush, true);
  296. } else {
  297. super.handleErrorFlush(errorOutputToFlush);
  298. }
  299. }
  300. /**
  301. * Do the execution.
  302. * @throws BuildException if a target tries to call itself;
  303. * probably also if a BuildException is thrown by the new project.
  304. */
  305. @Override
  306. public void execute() throws BuildException {
  307. File savedDir = dir;
  308. String savedAntFile = antFile;
  309. Vector<String> locals = new VectorSet<>(targets);
  310. try {
  311. getNewProject();
  312. if (dir == null && inheritAll) {
  313. dir = getProject().getBaseDir();
  314. }
  315. initializeProject();
  316. if (dir != null) {
  317. if (!useNativeBasedir) {
  318. newProject.setBaseDir(dir);
  319. if (savedDir != null) {
  320. // has been set explicitly
  321. newProject.setInheritedProperty(MagicNames.PROJECT_BASEDIR,
  322. dir.getAbsolutePath());
  323. }
  324. }
  325. } else {
  326. dir = getProject().getBaseDir();
  327. }
  328. overrideProperties();
  329. if (antFile == null) {
  330. antFile = getDefaultBuildFile();
  331. }
  332. File file = FILE_UTILS.resolveFile(dir, antFile);
  333. antFile = file.getAbsolutePath();
  334. log("calling target(s) "
  335. + (locals.isEmpty() ? "[default]" : locals.toString())
  336. + " in build file " + antFile, Project.MSG_VERBOSE);
  337. newProject.setUserProperty(MagicNames.ANT_FILE, antFile);
  338. String thisAntFile = getProject().getProperty(MagicNames.ANT_FILE);
  339. // Are we trying to call the target in which we are defined (or
  340. // the build file if this is a top level task)?
  341. if (thisAntFile != null && file.equals(getProject().resolveFile(thisAntFile))
  342. && getOwningTarget() != null && getOwningTarget().getName().isEmpty()) {
  343. if ("antcall".equals(getTaskName())) {
  344. throw new BuildException(
  345. "antcall must not be used at the top level.");
  346. }
  347. throw new BuildException(
  348. "%s task at the top level must not invoke its own build file.",
  349. getTaskName());
  350. }
  351. try {
  352. ProjectHelper.configureProject(newProject, file);
  353. } catch (BuildException ex) {
  354. throw ProjectHelper.addLocationToBuildException(
  355. ex, getLocation());
  356. }
  357. if (locals.isEmpty()) {
  358. String defaultTarget = newProject.getDefaultTarget();
  359. if (defaultTarget != null) {
  360. locals.add(defaultTarget);
  361. }
  362. }
  363. if (newProject.getProperty(MagicNames.ANT_FILE)
  364. .equals(getProject().getProperty(MagicNames.ANT_FILE))
  365. && getOwningTarget() != null) {
  366. String owningTargetName = getOwningTarget().getName();
  367. if (locals.contains(owningTargetName)) {
  368. throw new BuildException(
  369. "%s task calling its own parent target.",
  370. getTaskName());
  371. }
  372. final Map<String, Target> targetsMap = getProject().getTargets();
  373. if (locals.stream().map(targetsMap::get)
  374. .filter(Objects::nonNull)
  375. .anyMatch(other -> other.dependsOn(owningTargetName))) {
  376. throw new BuildException(
  377. "%s task calling a target that depends on its parent target '%s'.",
  378. getTaskName(), owningTargetName);
  379. }
  380. }
  381. addReferences();
  382. if (!locals.isEmpty() && !(locals.size() == 1
  383. && locals.get(0) != null && locals.get(0).isEmpty())) {
  384. BuildException be = null;
  385. try {
  386. log("Entering " + antFile + "...", Project.MSG_VERBOSE);
  387. newProject.fireSubBuildStarted();
  388. newProject.executeTargets(locals);
  389. } catch (BuildException ex) {
  390. be = ProjectHelper
  391. .addLocationToBuildException(ex, getLocation());
  392. throw be;
  393. } finally {
  394. log("Exiting " + antFile + ".", Project.MSG_VERBOSE);
  395. newProject.fireSubBuildFinished(be);
  396. }
  397. }
  398. } finally {
  399. // help the gc
  400. newProject = null;
  401. for (Property p : properties) {
  402. p.setProject(null);
  403. }
  404. if (output != null && out != null) {
  405. FileUtils.close(out);
  406. }
  407. dir = savedDir;
  408. antFile = savedAntFile;
  409. }
  410. }
  411. /**
  412. * Get the default build file name to use when launching the task.
  413. * <p>
  414. * This function may be overridden by providers of custom ProjectHelper so they can easily
  415. * implement their sublauncher.
  416. *
  417. * @return the name of the default file
  418. * @since Ant 1.8.0
  419. */
  420. protected String getDefaultBuildFile() {
  421. return Main.DEFAULT_BUILD_FILENAME;
  422. }
  423. /**
  424. * Override the properties in the new project with the one
  425. * explicitly defined as nested elements here.
  426. * @throws BuildException under unknown circumstances.
  427. */
  428. private void overrideProperties() throws BuildException {
  429. // remove duplicate properties - last property wins
  430. // Needed for backward compatibility
  431. Set<String> set = new HashSet<>();
  432. for (int i = properties.size() - 1; i >= 0; --i) {
  433. Property p = properties.get(i);
  434. if (p.getName() != null && !p.getName().isEmpty()) {
  435. if (set.contains(p.getName())) {
  436. properties.remove(i);
  437. } else {
  438. set.add(p.getName());
  439. }
  440. }
  441. }
  442. properties.stream().peek(p -> p.setProject(newProject))
  443. .forEach(Property::execute);
  444. if (useNativeBasedir) {
  445. addAlmostAll(getProject().getInheritedProperties(),
  446. PropertyType.INHERITED);
  447. } else {
  448. getProject().copyInheritedProperties(newProject);
  449. }
  450. }
  451. /**
  452. * Add the references explicitly defined as nested elements to the
  453. * new project. Also copy over all references that don't override
  454. * existing references in the new project if inheritrefs has been
  455. * requested.
  456. * @throws BuildException if a reference does not have a refid.
  457. */
  458. private void addReferences() throws BuildException {
  459. Map<String, Object> thisReferences =
  460. new HashMap<>(getProject().getReferences());
  461. for (Reference ref : references) {
  462. String refid = ref.getRefId();
  463. if (refid == null) {
  464. throw new BuildException(
  465. "the refid attribute is required for reference elements");
  466. }
  467. if (!thisReferences.containsKey(refid)) {
  468. log("Parent project doesn't contain any reference '"
  469. + refid + "'",
  470. Project.MSG_WARN);
  471. continue;
  472. }
  473. thisReferences.remove(refid);
  474. String toRefid = ref.getToRefid();
  475. if (toRefid == null) {
  476. toRefid = refid;
  477. }
  478. copyReference(refid, toRefid);
  479. }
  480. // Now add all references that are not defined in the
  481. // subproject, if inheritRefs is true
  482. if (inheritRefs) {
  483. Map<String, Object> newReferences = newProject.getReferences();
  484. for (String key : thisReferences.keySet()) {
  485. if (newReferences.containsKey(key)) {
  486. continue;
  487. }
  488. copyReference(key, key);
  489. newProject.inheritIDReferences(getProject());
  490. }
  491. }
  492. }
  493. /**
  494. * Try to clone and reconfigure the object referenced by oldkey in
  495. * the parent project and add it to the new project with the key newkey.
  496. *
  497. * <p>If we cannot clone it, copy the referenced object itself and
  498. * keep our fingers crossed.</p>
  499. * @param oldKey the reference id in the current project.
  500. * @param newKey the reference id in the new project.
  501. */
  502. private void copyReference(String oldKey, String newKey) {
  503. Object orig = getProject().getReference(oldKey);
  504. if (orig == null) {
  505. log("No object referenced by " + oldKey + ". Can't copy to "
  506. + newKey,
  507. Project.MSG_WARN);
  508. return;
  509. }
  510. Class<?> c = orig.getClass();
  511. Object copy = orig;
  512. try {
  513. Method cloneM = c.getMethod("clone");
  514. if (cloneM != null) {
  515. copy = cloneM.invoke(orig);
  516. log("Adding clone of reference " + oldKey, Project.MSG_DEBUG);
  517. }
  518. } catch (Exception e) {
  519. // not Clonable
  520. }
  521. if (copy instanceof ProjectComponent) {
  522. ((ProjectComponent) copy).setProject(newProject);
  523. } else {
  524. try {
  525. Method setProjectM =
  526. c.getMethod("setProject", Project.class);
  527. if (setProjectM != null) {
  528. setProjectM.invoke(copy, newProject);
  529. }
  530. } catch (NoSuchMethodException e) {
  531. // ignore this if the class being referenced does not have
  532. // a set project method.
  533. } catch (Exception e2) {
  534. throw new BuildException(
  535. "Error setting new project instance for "
  536. + "reference with id " + oldKey,
  537. e2, getLocation());
  538. }
  539. }
  540. newProject.addReference(newKey, copy);
  541. }
  542. /**
  543. * Copies all properties from the given table to the new project -
  544. * omitting those that have already been set in the new project as
  545. * well as properties named basedir or ant.file.
  546. * @param props properties <code>Hashtable</code> to copy to the
  547. * new project.
  548. * @param type the type of property to set (a plain Ant property, a
  549. * user property or an inherited property).
  550. * @since Ant 1.8.0
  551. */
  552. private void addAlmostAll(Map<?, ?> props, PropertyType type) {
  553. props.forEach((k, v) -> {
  554. String key = k.toString();
  555. if (MagicNames.PROJECT_BASEDIR.equals(key)
  556. || MagicNames.ANT_FILE.equals(key)) {
  557. // basedir and ant.file get special treatment in execute()
  558. return;
  559. }
  560. String value = v.toString();
  561. switch (type) {
  562. case PLAIN:
  563. // don't re-set user properties, avoid the warning message
  564. if (newProject.getProperty(key) == null) {
  565. // no user property
  566. newProject.setNewProperty(key, value);
  567. }
  568. break;
  569. case USER:
  570. newProject.setUserProperty(key, value);
  571. break;
  572. case INHERITED:
  573. newProject.setInheritedProperty(key, value);
  574. break;
  575. }
  576. });
  577. }
  578. /**
  579. * The directory to use as a base directory for the new Ant project.
  580. * Defaults to the current project's basedir, unless inheritall
  581. * has been set to false, in which case it doesn't have a default
  582. * value. This will override the basedir setting of the called project.
  583. * @param dir new directory as <code>File</code>.
  584. */
  585. public void setDir(File dir) {
  586. this.dir = dir;
  587. }
  588. /**
  589. * The build file to use. Defaults to "build.xml". This file is expected
  590. * to be a filename relative to the dir attribute given.
  591. * @param antFile the <code>String</code> build file name.
  592. */
  593. public void setAntfile(String antFile) {
  594. // @note: it is a string and not a file to handle relative/absolute
  595. // otherwise a relative file will be resolved based on the current
  596. // basedir.
  597. this.antFile = antFile;
  598. }
  599. /**
  600. * The target of the new Ant project to execute.
  601. * Defaults to the new project's default target.
  602. * @param targetToAdd the name of the target to invoke.
  603. */
  604. public void setTarget(String targetToAdd) {
  605. if (targetToAdd.isEmpty()) {
  606. throw new BuildException("target attribute must not be empty");
  607. }
  608. targets.add(targetToAdd);
  609. targetAttributeSet = true;
  610. }
  611. /**
  612. * Set the filename to write the output to. This is relative to the value
  613. * of the dir attribute if it has been set or to the base directory of the
  614. * current project otherwise.
  615. * @param outputFile the name of the file to which the output should go.
  616. */
  617. public void setOutput(String outputFile) {
  618. this.output = outputFile;
  619. }
  620. /**
  621. * Property to pass to the new project.
  622. * The property is passed as a 'user property'.
  623. * @return the created <code>Property</code> object.
  624. */
  625. public Property createProperty() {
  626. Property p = new Property(true, getProject());
  627. p.setProject(getNewProject());
  628. p.setTaskName("property");
  629. properties.add(p);
  630. return p;
  631. }
  632. /**
  633. * Add a Reference element identifying a data type to carry
  634. * over to the new project.
  635. * @param ref <code>Reference</code> to add.
  636. */
  637. public void addReference(Reference ref) {
  638. references.add(ref);
  639. }
  640. /**
  641. * Add a target to this Ant invocation.
  642. * @param t the <code>TargetElement</code> to add.
  643. * @since Ant 1.6.3
  644. */
  645. public void addConfiguredTarget(TargetElement t) {
  646. if (targetAttributeSet) {
  647. throw new BuildException(
  648. "nested target is incompatible with the target attribute");
  649. }
  650. String name = t.getName();
  651. if (name.isEmpty()) {
  652. throw new BuildException("target name must not be empty");
  653. }
  654. targets.add(name);
  655. }
  656. /**
  657. * Add a set of properties to pass to the new project.
  658. *
  659. * @param ps <code>PropertySet</code> to add.
  660. * @since Ant 1.6
  661. */
  662. public void addPropertyset(PropertySet ps) {
  663. propertySets.add(ps);
  664. }
  665. /**
  666. * Get the (sub)-Project instance currently in use.
  667. * @return Project
  668. * @since Ant 1.7
  669. */
  670. protected Project getNewProject() {
  671. if (newProject == null) {
  672. reinit();
  673. }
  674. return newProject;
  675. }
  676. /**
  677. * @since Ant 1.6.2
  678. */
  679. private Iterator<BuildListener> getBuildListeners() {
  680. return getProject().getBuildListeners().iterator();
  681. }
  682. /**
  683. * Helper class that implements the nested &lt;reference&gt;
  684. * element of &lt;ant&gt; and &lt;antcall&gt;.
  685. */
  686. @SuppressWarnings("deprecation")
  687. public static class Reference
  688. extends org.apache.tools.ant.types.Reference {
  689. private String targetid = null;
  690. /**
  691. * Set the id that this reference to be stored under in the
  692. * new project.
  693. *
  694. * @param targetid the id under which this reference will be passed to
  695. * the new project. */
  696. public void setToRefid(String targetid) {
  697. this.targetid = targetid;
  698. }
  699. /**
  700. * Get the id under which this reference will be stored in the new
  701. * project.
  702. *
  703. * @return the id of the reference in the new project.
  704. */
  705. public String getToRefid() {
  706. return targetid;
  707. }
  708. }
  709. /**
  710. * Helper class that implements the nested &lt;target&gt;
  711. * element of &lt;ant&gt; and &lt;antcall&gt;.
  712. * @since Ant 1.6.3
  713. */
  714. public static class TargetElement {
  715. private String name;
  716. /**
  717. * Default constructor.
  718. */
  719. public TargetElement() {
  720. //default
  721. }
  722. /**
  723. * Set the name of this TargetElement.
  724. * @param name the <code>String</code> target name.
  725. */
  726. public void setName(String name) {
  727. this.name = name;
  728. }
  729. /**
  730. * Get the name of this TargetElement.
  731. * @return <code>String</code>.
  732. */
  733. public String getName() {
  734. return name;
  735. }
  736. }
  737. private enum PropertyType {
  738. PLAIN, INHERITED, USER
  739. }
  740. }