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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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. * @ant:task category="control"
  91. */
  92. public class Ant extends Task {
  93. /** the basedir where is executed the build file */
  94. private File dir = null;
  95. /** the build.xml file (can be absolute) in this case dir will be ignored */
  96. private String antFile = null;
  97. /** the target to call if any */
  98. private String target = null;
  99. /** the output */
  100. private String output = null;
  101. /** should we inherit properties from the parent ? */
  102. private boolean inheritAll = true;
  103. /** should we inherit references from the parent ? */
  104. private boolean inheritRefs = false;
  105. /** the properties to pass to the new project */
  106. private Vector properties = new Vector();
  107. /** the references to pass to the new project */
  108. private Vector references = new Vector();
  109. /** the temporary project created to run the build file */
  110. private Project newProject;
  111. /**
  112. * If true, inherit all properties from parent Project
  113. * If false, inherit only userProperties and those defined
  114. * inside the ant call itself
  115. */
  116. public void setInheritAll(boolean value) {
  117. inheritAll = value;
  118. }
  119. /**
  120. * If true, inherit all references from parent Project
  121. * If false, inherit only those defined
  122. * inside the ant call itself
  123. */
  124. public void setInheritRefs(boolean value) {
  125. inheritRefs = value;
  126. }
  127. public void init() {
  128. newProject = new Project();
  129. newProject.setJavaVersionProperty();
  130. newProject.addTaskDefinition("property",
  131. (Class)project.getTaskDefinitions().get("property"));
  132. }
  133. private void reinit() {
  134. init();
  135. final int count = properties.size();
  136. for (int i = 0; i < count; i++) {
  137. Property p = (Property) properties.elementAt(i);
  138. Property newP = (Property) newProject.createTask("property");
  139. newP.setName(p.getName());
  140. if (p.getValue() != null) {
  141. newP.setValue(p.getValue());
  142. }
  143. if (p.getFile() != null) {
  144. newP.setFile(p.getFile());
  145. }
  146. if (p.getResource() != null) {
  147. newP.setResource(p.getResource());
  148. }
  149. properties.setElementAt(newP, i);
  150. }
  151. }
  152. private void initializeProject() {
  153. Vector listeners = project.getBuildListeners();
  154. final int count = listeners.size();
  155. for (int i = 0; i < count; i++) {
  156. newProject.addBuildListener((BuildListener)listeners.elementAt(i));
  157. }
  158. if (output != null) {
  159. try {
  160. PrintStream out = new PrintStream(new FileOutputStream(output));
  161. DefaultLogger logger = new DefaultLogger();
  162. logger.setMessageOutputLevel(Project.MSG_INFO);
  163. logger.setOutputPrintStream(out);
  164. logger.setErrorPrintStream(out);
  165. newProject.addBuildListener(logger);
  166. }
  167. catch( IOException ex ) {
  168. log( "Ant: Can't set output to " + output );
  169. }
  170. }
  171. Hashtable taskdefs = project.getTaskDefinitions();
  172. Enumeration et = taskdefs.keys();
  173. while (et.hasMoreElements()) {
  174. String taskName = (String) et.nextElement();
  175. if (taskName.equals("property")) {
  176. // we have already added this taskdef in #init
  177. continue;
  178. }
  179. Class taskClass = (Class) taskdefs.get(taskName);
  180. newProject.addTaskDefinition(taskName, taskClass);
  181. }
  182. Hashtable typedefs = project.getDataTypeDefinitions();
  183. Enumeration e = typedefs.keys();
  184. while (e.hasMoreElements()) {
  185. String typeName = (String) e.nextElement();
  186. Class typeClass = (Class) typedefs.get(typeName);
  187. newProject.addDataTypeDefinition(typeName, typeClass);
  188. }
  189. // set user-defined or all properties from calling project
  190. Hashtable prop1;
  191. if (inheritAll) {
  192. prop1 = project.getProperties();
  193. } else {
  194. prop1 = project.getUserProperties();
  195. // set Java built-in properties separately,
  196. // b/c we won't inherit them.
  197. newProject.setSystemProperties();
  198. }
  199. e = prop1.keys();
  200. while (e.hasMoreElements()) {
  201. String arg = (String) e.nextElement();
  202. if ("basedir".equals(arg) || "ant.file".equals(arg)) {
  203. // basedir and ant.file get special treatment in execute()
  204. continue;
  205. }
  206. String value = (String) prop1.get(arg);
  207. if (inheritAll){
  208. newProject.setProperty(arg, value);
  209. } else {
  210. newProject.setUserProperty(arg, value);
  211. }
  212. }
  213. }
  214. protected void handleOutput(String line) {
  215. if (newProject != null) {
  216. newProject.demuxOutput(line, false);
  217. } else {
  218. super.handleOutput(line);
  219. }
  220. }
  221. protected void handleErrorOutput(String line) {
  222. if (newProject != null) {
  223. newProject.demuxOutput(line, true);
  224. } else {
  225. super.handleErrorOutput(line);
  226. }
  227. }
  228. /**
  229. * Do the execution.
  230. */
  231. public void execute() throws BuildException {
  232. try {
  233. if (newProject == null) {
  234. reinit();
  235. }
  236. if ( (dir == null) && (inheritAll) ) {
  237. dir = project.getBaseDir();
  238. }
  239. initializeProject();
  240. if (dir != null) {
  241. newProject.setBaseDir(dir);
  242. newProject.setUserProperty("basedir" , dir.getAbsolutePath());
  243. } else {
  244. dir = project.getBaseDir();
  245. }
  246. overrideProperties();
  247. if (antFile == null) {
  248. antFile = "build.xml";
  249. }
  250. File file = FileUtils.newFileUtils().resolveFile(dir, antFile);
  251. antFile = file.getAbsolutePath();
  252. log("calling target "+(target!=null?target:"[default]")
  253. + " in build file "+ antFile.toString(),
  254. Project.MSG_VERBOSE);
  255. newProject.setUserProperty( "ant.file" , antFile );
  256. ProjectHelper.configureProject(newProject, new File(antFile));
  257. if (target == null) {
  258. target = newProject.getDefaultTarget();
  259. }
  260. addReferences();
  261. // Are we trying to call the target in which we are defined?
  262. if (newProject.getBaseDir().equals(project.getBaseDir()) &&
  263. newProject.getProperty("ant.file").equals(project.getProperty("ant.file")) &&
  264. getOwningTarget() != null &&
  265. target.equals(this.getOwningTarget().getName())) {
  266. throw new BuildException("ant task calling its own parent target");
  267. }
  268. newProject.executeTarget(target);
  269. } finally {
  270. // help the gc
  271. newProject = null;
  272. }
  273. }
  274. /**
  275. * Override the properties in the new project with the one
  276. * explicitly defined as nested elements here.
  277. */
  278. private void overrideProperties() throws BuildException {
  279. Enumeration e = properties.elements();
  280. while (e.hasMoreElements()) {
  281. Property p = (Property) e.nextElement();
  282. p.setProject(newProject);
  283. p.execute();
  284. }
  285. }
  286. /**
  287. * Add the references explicitly defined as nested elements to the
  288. * new project. Also copy over all references that don't override
  289. * existing references in the new project if inheritall has been
  290. * requested.
  291. */
  292. private void addReferences() throws BuildException {
  293. Hashtable thisReferences = (Hashtable) project.getReferences().clone();
  294. Hashtable newReferences = newProject.getReferences();
  295. Enumeration e;
  296. if (references.size() > 0) {
  297. for(e = references.elements(); e.hasMoreElements();) {
  298. Reference ref = (Reference)e.nextElement();
  299. String refid = ref.getRefId();
  300. if (refid == null) {
  301. throw new BuildException("the refid attribute is required for reference elements");
  302. }
  303. if (!thisReferences.containsKey(refid)) {
  304. log("Parent project doesn't contain any reference '"
  305. + refid + "'",
  306. Project.MSG_WARN);
  307. continue;
  308. }
  309. thisReferences.remove(refid);
  310. String toRefid = ref.getToRefid();
  311. if (toRefid == null) {
  312. toRefid = refid;
  313. }
  314. copyReference(refid, toRefid);
  315. }
  316. }
  317. // Now add all references that are not defined in the
  318. // subproject, if inheritRefs is true
  319. if (inheritRefs) {
  320. for(e = thisReferences.keys(); e.hasMoreElements();) {
  321. String key = (String)e.nextElement();
  322. if (newReferences.containsKey(key)) {
  323. continue;
  324. }
  325. copyReference(key, key);
  326. }
  327. }
  328. }
  329. /**
  330. * Try to clone and reconfigure the object referenced by oldkey in
  331. * the parent project and add it to the new project with the key
  332. * newkey.
  333. *
  334. * <p>If we cannot clone it, copy the referenced object itself and
  335. * keep our fingers crossed.</p>
  336. */
  337. private void copyReference(String oldKey, String newKey) {
  338. Object orig = project.getReference(oldKey);
  339. Class c = orig.getClass();
  340. Object copy = orig;
  341. try {
  342. Method cloneM = c.getMethod("clone", new Class[0]);
  343. if (cloneM != null) {
  344. copy = cloneM.invoke(orig, new Object[0]);
  345. }
  346. } catch (Exception e) {
  347. // not Clonable
  348. }
  349. if (copy instanceof ProjectComponent) {
  350. ((ProjectComponent) copy).setProject(newProject);
  351. } else {
  352. try {
  353. Method setProjectM =
  354. c.getMethod( "setProject", new Class[] {Project.class});
  355. if(setProjectM != null) {
  356. setProjectM.invoke(copy, new Object[] {newProject});
  357. }
  358. } catch (NoSuchMethodException e) {
  359. // ignore this if the class being referenced does not have
  360. // a set project method.
  361. } catch(Exception e2) {
  362. String msg = "Error setting new project instance for reference with id "
  363. + oldKey;
  364. throw new BuildException(msg, e2, location);
  365. }
  366. }
  367. newProject.addReference(newKey, copy);
  368. }
  369. /**
  370. * ...
  371. */
  372. public void setDir(File d) {
  373. this.dir = d;
  374. }
  375. /**
  376. * set the build file, it can be either absolute or relative.
  377. * If it is absolute, <tt>dir</tt> will be ignored, if it is
  378. * relative it will be resolved relative to <tt>dir</tt>.
  379. */
  380. public void setAntfile(String s) {
  381. // @note: it is a string and not a file to handle relative/absolute
  382. // otherwise a relative file will be resolved based on the current
  383. // basedir.
  384. this.antFile = s;
  385. }
  386. /**
  387. * set the target to execute. If none is defined it will
  388. * execute the default target of the build file
  389. */
  390. public void setTarget(String s) {
  391. this.target = s;
  392. }
  393. public void setOutput(String s) {
  394. this.output = s;
  395. }
  396. /** create a property to pass to the new project as a 'user property' */
  397. public Property createProperty() {
  398. if (newProject == null) {
  399. reinit();
  400. }
  401. Property p = new Property(true);
  402. p.setProject(newProject);
  403. p.setTaskName("property");
  404. properties.addElement( p );
  405. return p;
  406. }
  407. /**
  408. * create a reference element that identifies a data type that
  409. * should be carried over to the new project.
  410. */
  411. public void addReference(Reference r) {
  412. references.addElement(r);
  413. }
  414. /**
  415. * Helper class that implements the nested &lt;reference&gt;
  416. * element of &lt;ant&gt; and &lt;antcall&gt;.
  417. */
  418. public static class Reference
  419. extends org.apache.tools.ant.types.Reference {
  420. public Reference() {super();}
  421. private String targetid=null;
  422. public void setToRefid(String targetid) { this.targetid=targetid; }
  423. public String getToRefid() { return targetid; }
  424. }
  425. }