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 18 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.taskdefs;
  55. import org.apache.tools.ant.Task;
  56. import org.apache.tools.ant.Project;
  57. import org.apache.tools.ant.ProjectComponent;
  58. import org.apache.tools.ant.BuildListener;
  59. import org.apache.tools.ant.DefaultLogger;
  60. import org.apache.tools.ant.BuildException;
  61. import org.apache.tools.ant.ProjectHelper;
  62. import org.apache.tools.ant.util.FileUtils;
  63. import java.io.File;
  64. import java.io.PrintStream;
  65. import java.io.FileOutputStream;
  66. import java.io.IOException;
  67. import java.lang.reflect.Method;
  68. import java.util.Vector;
  69. import java.util.Hashtable;
  70. import java.util.Enumeration;
  71. /**
  72. * Call Ant in a sub-project.
  73. *
  74. * <pre>
  75. * &lt;target name=&quot;foo&quot; depends=&quot;init&quot;&gt;
  76. * &lt;ant antfile=&quot;build.xml&quot; target=&quot;bar&quot; &gt;
  77. * &lt;property name=&quot;property1&quot; value=&quot;aaaaa&quot; /&gt;
  78. * &lt;property name=&quot;foo&quot; value=&quot;baz&quot; /&gt;
  79. * &lt;/ant&gt;</SPAN>
  80. * &lt;/target&gt;</SPAN>
  81. *
  82. * &lt;target name=&quot;bar&quot; depends=&quot;init&quot;&gt;
  83. * &lt;echo message=&quot;prop is ${property1} ${foo}&quot; /&gt;
  84. * &lt;/target&gt;
  85. * </pre>
  86. *
  87. *
  88. * @author costin@dnt.ro
  89. *
  90. * @since Ant 1.1
  91. *
  92. * @ant.task category="control"
  93. */
  94. public class Ant extends Task {
  95. /** the basedir where is executed the build file */
  96. private File dir = null;
  97. /**
  98. * the build.xml file (can be absolute) in this case dir will be
  99. * ignored
  100. */
  101. private String antFile = null;
  102. /** the target to call if any */
  103. private String target = null;
  104. /** the output */
  105. private String output = null;
  106. /** should we inherit properties from the parent ? */
  107. private boolean inheritAll = true;
  108. /** should we inherit references from the parent ? */
  109. private boolean inheritRefs = false;
  110. /** the properties to pass to the new project */
  111. private Vector properties = new Vector();
  112. /** the references to pass to the new project */
  113. private Vector references = new Vector();
  114. /** the temporary project created to run the build file */
  115. private Project newProject;
  116. /** The stream to which output is to be written. */
  117. private PrintStream out = null;
  118. /**
  119. * If true, inherit all properties from parent Project
  120. * If false, inherit only userProperties and those defined
  121. * inside the ant call itself
  122. */
  123. public void setInheritAll(boolean value) {
  124. inheritAll = value;
  125. }
  126. /**
  127. * If true, inherit all references from parent Project
  128. * If false, inherit only those defined
  129. * inside the ant call itself
  130. */
  131. public void setInheritRefs(boolean value) {
  132. inheritRefs = value;
  133. }
  134. /**
  135. * Creates a Project instance for the project to call.
  136. */
  137. public void init() {
  138. newProject = new Project();
  139. newProject.setJavaVersionProperty();
  140. newProject.addTaskDefinition("property",
  141. (Class) project.getTaskDefinitions()
  142. .get("property"));
  143. }
  144. /**
  145. * Called in execute or createProperty if newProject is null.
  146. *
  147. * <p>This can happen if the same instance of this task is run
  148. * twice as newProject is set to null at the end of execute (to
  149. * save memory and help the GC).</p>
  150. *
  151. * <p>Sets all properties that have been defined as nested
  152. * property elements.</p>
  153. */
  154. private void reinit() {
  155. init();
  156. final int count = properties.size();
  157. for (int i = 0; i < count; i++) {
  158. Property p = (Property) properties.elementAt(i);
  159. Property newP = (Property) newProject.createTask("property");
  160. newP.setName(p.getName());
  161. if (p.getValue() != null) {
  162. newP.setValue(p.getValue());
  163. }
  164. if (p.getFile() != null) {
  165. newP.setFile(p.getFile());
  166. }
  167. if (p.getResource() != null) {
  168. newP.setResource(p.getResource());
  169. }
  170. properties.setElementAt(newP, i);
  171. }
  172. }
  173. /**
  174. * Attaches the build listeners of the current project to the new
  175. * project, configures a possible logfile, transfers task and
  176. * data-type definitions, transfers properties (either all or just
  177. * the ones specified as user properties to the current project,
  178. * depending on inheritall).
  179. */
  180. private void initializeProject() {
  181. Vector listeners = project.getBuildListeners();
  182. final int count = listeners.size();
  183. for (int i = 0; i < count; i++) {
  184. newProject.addBuildListener((BuildListener)listeners.elementAt(i));
  185. }
  186. if (output != null) {
  187. File outfile = null;
  188. if (dir != null) {
  189. outfile = FileUtils.newFileUtils().resolveFile(dir, output);
  190. } else {
  191. outfile = getProject().resolveFile(output);
  192. }
  193. try {
  194. out = new PrintStream(new FileOutputStream(outfile));
  195. DefaultLogger logger = new DefaultLogger();
  196. logger.setMessageOutputLevel(Project.MSG_INFO);
  197. logger.setOutputPrintStream(out);
  198. logger.setErrorPrintStream(out);
  199. newProject.addBuildListener(logger);
  200. }
  201. catch( IOException ex ) {
  202. log( "Ant: Can't set output to " + output );
  203. }
  204. }
  205. Hashtable taskdefs = project.getTaskDefinitions();
  206. Enumeration et = taskdefs.keys();
  207. while (et.hasMoreElements()) {
  208. String taskName = (String) et.nextElement();
  209. if (taskName.equals("property")) {
  210. // we have already added this taskdef in #init
  211. continue;
  212. }
  213. Class taskClass = (Class) taskdefs.get(taskName);
  214. newProject.addTaskDefinition(taskName, taskClass);
  215. }
  216. Hashtable typedefs = project.getDataTypeDefinitions();
  217. Enumeration e = typedefs.keys();
  218. while (e.hasMoreElements()) {
  219. String typeName = (String) e.nextElement();
  220. Class typeClass = (Class) typedefs.get(typeName);
  221. newProject.addDataTypeDefinition(typeName, typeClass);
  222. }
  223. // set user-defined or all properties from calling project
  224. Hashtable prop1;
  225. if (inheritAll) {
  226. prop1 = project.getProperties();
  227. } else {
  228. prop1 = project.getUserProperties();
  229. // set Java built-in properties separately,
  230. // b/c we won't inherit them.
  231. newProject.setSystemProperties();
  232. }
  233. e = prop1.keys();
  234. while (e.hasMoreElements()) {
  235. String arg = (String) e.nextElement();
  236. if ("basedir".equals(arg) || "ant.file".equals(arg)) {
  237. // basedir and ant.file get special treatment in execute()
  238. continue;
  239. }
  240. String value = (String) prop1.get(arg);
  241. if (inheritAll){
  242. newProject.setProperty(arg, value);
  243. } else {
  244. newProject.setUserProperty(arg, value);
  245. }
  246. }
  247. }
  248. /**
  249. * Pass output sent to System.out to the new project.
  250. *
  251. * @since Ant 1.5
  252. */
  253. protected void handleOutput(String line) {
  254. if (newProject != null) {
  255. newProject.demuxOutput(line, false);
  256. } else {
  257. super.handleOutput(line);
  258. }
  259. }
  260. /**
  261. * Pass output sent to System.err to the new project.
  262. *
  263. * @since Ant 1.5
  264. */
  265. protected void handleErrorOutput(String line) {
  266. if (newProject != null) {
  267. newProject.demuxOutput(line, true);
  268. } else {
  269. super.handleErrorOutput(line);
  270. }
  271. }
  272. /**
  273. * Do the execution.
  274. */
  275. public void execute() throws BuildException {
  276. File savedDir = dir;
  277. String savedAntFile = antFile;
  278. String savedTarget = target;
  279. try {
  280. if (newProject == null) {
  281. reinit();
  282. }
  283. if ( (dir == null) && (inheritAll) ) {
  284. dir = project.getBaseDir();
  285. }
  286. initializeProject();
  287. if (dir != null) {
  288. newProject.setBaseDir(dir);
  289. newProject.setUserProperty("basedir" , dir.getAbsolutePath());
  290. } else {
  291. dir = project.getBaseDir();
  292. }
  293. overrideProperties();
  294. if (antFile == null) {
  295. antFile = "build.xml";
  296. }
  297. File file = FileUtils.newFileUtils().resolveFile(dir, antFile);
  298. antFile = file.getAbsolutePath();
  299. log("calling target "+(target!=null?target:"[default]")
  300. + " in build file "+ antFile.toString(),
  301. Project.MSG_VERBOSE);
  302. newProject.setUserProperty( "ant.file" , antFile );
  303. ProjectHelper.configureProject(newProject, new File(antFile));
  304. if (target == null) {
  305. target = newProject.getDefaultTarget();
  306. }
  307. addReferences();
  308. // Are we trying to call the target in which we are defined?
  309. if (newProject.getBaseDir().equals(project.getBaseDir()) &&
  310. newProject.getProperty("ant.file").equals(project.getProperty("ant.file")) &&
  311. getOwningTarget() != null &&
  312. target.equals(this.getOwningTarget().getName())) {
  313. throw new BuildException("ant task calling its own parent target");
  314. }
  315. newProject.executeTarget(target);
  316. } finally {
  317. // help the gc
  318. newProject = null;
  319. if (output != null && out != null) {
  320. try {
  321. out.close();
  322. } catch (final Exception e) {
  323. //ignore
  324. }
  325. }
  326. dir = savedDir;
  327. antFile = savedAntFile;
  328. target = savedTarget;
  329. }
  330. }
  331. /**
  332. * Override the properties in the new project with the one
  333. * explicitly defined as nested elements here.
  334. */
  335. private void overrideProperties() throws BuildException {
  336. Enumeration e = properties.elements();
  337. while (e.hasMoreElements()) {
  338. Property p = (Property) e.nextElement();
  339. p.setProject(newProject);
  340. p.execute();
  341. }
  342. }
  343. /**
  344. * Add the references explicitly defined as nested elements to the
  345. * new project. Also copy over all references that don't override
  346. * existing references in the new project if inheritrefs has been
  347. * requested.
  348. */
  349. private void addReferences() throws BuildException {
  350. Hashtable thisReferences = (Hashtable) project.getReferences().clone();
  351. Hashtable newReferences = newProject.getReferences();
  352. Enumeration e;
  353. if (references.size() > 0) {
  354. for(e = references.elements(); e.hasMoreElements();) {
  355. Reference ref = (Reference)e.nextElement();
  356. String refid = ref.getRefId();
  357. if (refid == null) {
  358. throw new BuildException("the refid attribute is required"
  359. + " for reference elements");
  360. }
  361. if (!thisReferences.containsKey(refid)) {
  362. log("Parent project doesn't contain any reference '"
  363. + refid + "'",
  364. Project.MSG_WARN);
  365. continue;
  366. }
  367. thisReferences.remove(refid);
  368. String toRefid = ref.getToRefid();
  369. if (toRefid == null) {
  370. toRefid = refid;
  371. }
  372. copyReference(refid, toRefid);
  373. }
  374. }
  375. // Now add all references that are not defined in the
  376. // subproject, if inheritRefs is true
  377. if (inheritRefs) {
  378. for(e = thisReferences.keys(); e.hasMoreElements();) {
  379. String key = (String)e.nextElement();
  380. if (newReferences.containsKey(key)) {
  381. continue;
  382. }
  383. copyReference(key, key);
  384. }
  385. }
  386. }
  387. /**
  388. * Try to clone and reconfigure the object referenced by oldkey in
  389. * the parent project and add it to the new project with the key
  390. * newkey.
  391. *
  392. * <p>If we cannot clone it, copy the referenced object itself and
  393. * keep our fingers crossed.</p>
  394. */
  395. private void copyReference(String oldKey, String newKey) {
  396. Object orig = project.getReference(oldKey);
  397. Class c = orig.getClass();
  398. Object copy = orig;
  399. try {
  400. Method cloneM = c.getMethod("clone", new Class[0]);
  401. if (cloneM != null) {
  402. copy = cloneM.invoke(orig, new Object[0]);
  403. }
  404. } catch (Exception e) {
  405. // not Clonable
  406. }
  407. if (copy instanceof ProjectComponent) {
  408. ((ProjectComponent) copy).setProject(newProject);
  409. } else {
  410. try {
  411. Method setProjectM =
  412. c.getMethod( "setProject", new Class[] {Project.class});
  413. if(setProjectM != null) {
  414. setProjectM.invoke(copy, new Object[] {newProject});
  415. }
  416. } catch (NoSuchMethodException e) {
  417. // ignore this if the class being referenced does not have
  418. // a set project method.
  419. } catch(Exception e2) {
  420. String msg = "Error setting new project instance for "
  421. + "reference with id " + oldKey;
  422. throw new BuildException(msg, e2, location);
  423. }
  424. }
  425. newProject.addReference(newKey, copy);
  426. }
  427. /**
  428. * Set the dir attribute.
  429. */
  430. public void setDir(File d) {
  431. this.dir = d;
  432. }
  433. /**
  434. * set the build file, it can be either absolute or relative.
  435. * If it is absolute, <tt>dir</tt> will be ignored, if it is
  436. * relative it will be resolved relative to <tt>dir</tt>.
  437. */
  438. public void setAntfile(String s) {
  439. // @note: it is a string and not a file to handle relative/absolute
  440. // otherwise a relative file will be resolved based on the current
  441. // basedir.
  442. this.antFile = s;
  443. }
  444. /**
  445. * set the target to execute. If none is defined it will
  446. * execute the default target of the build file
  447. */
  448. public void setTarget(String s) {
  449. this.target = s;
  450. }
  451. /**
  452. * Set the name of a log file. This will be resolved relative to
  453. * the dir attribute if specified, relative to the current
  454. * project's basedir otherwise.
  455. */
  456. public void setOutput(String s) {
  457. this.output = s;
  458. }
  459. /** create a property to pass to the new project as a 'user property' */
  460. public Property createProperty() {
  461. if (newProject == null) {
  462. reinit();
  463. }
  464. Property p = new Property(true);
  465. p.setProject(newProject);
  466. p.setTaskName("property");
  467. properties.addElement( p );
  468. return p;
  469. }
  470. /**
  471. * create a reference element that identifies a data type that
  472. * should be carried over to the new project.
  473. */
  474. public void addReference(Reference r) {
  475. references.addElement(r);
  476. }
  477. /**
  478. * Helper class that implements the nested &lt;reference&gt;
  479. * element of &lt;ant&gt; and &lt;antcall&gt;.
  480. */
  481. public static class Reference
  482. extends org.apache.tools.ant.types.Reference {
  483. public Reference() {super();}
  484. private String targetid=null;
  485. public void setToRefid(String targetid) { this.targetid=targetid; }
  486. public String getToRefid() { return targetid; }
  487. }
  488. }