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.

Project.java 35 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 1999 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;
  55. import java.io.*;
  56. import java.util.*;
  57. import java.text.*;
  58. import org.apache.tools.ant.types.FilterSet;
  59. import org.apache.tools.ant.types.FilterSetCollection;
  60. import org.apache.tools.ant.util.FileUtils;
  61. /**
  62. * Central representation of an Ant project. This class defines a
  63. * Ant project with all of it's targets and tasks. It also provides
  64. * the mechanism to kick off a build using a particular target name.
  65. * <p>
  66. * This class also encapsulates methods which allow Files to be refered
  67. * to using abstract path names which are translated to native system
  68. * file paths at runtime as well as defining various project properties.
  69. *
  70. * @author duncan@x180.com
  71. */
  72. public class Project {
  73. public static final int MSG_ERR = 0;
  74. public static final int MSG_WARN = 1;
  75. public static final int MSG_INFO = 2;
  76. public static final int MSG_VERBOSE = 3;
  77. public static final int MSG_DEBUG = 4;
  78. // private set of constants to represent the state
  79. // of a DFS of the Target dependencies
  80. private static final String VISITING = "VISITING";
  81. private static final String VISITED = "VISITED";
  82. private static String javaVersion;
  83. public static final String JAVA_1_0 = "1.0";
  84. public static final String JAVA_1_1 = "1.1";
  85. public static final String JAVA_1_2 = "1.2";
  86. public static final String JAVA_1_3 = "1.3";
  87. public static final String JAVA_1_4 = "1.4";
  88. public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
  89. public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
  90. private String name;
  91. private String description;
  92. private Hashtable properties = new Hashtable();
  93. private Hashtable userProperties = new Hashtable();
  94. private Hashtable references = new Hashtable();
  95. private String defaultTarget;
  96. private Hashtable dataClassDefinitions = new Hashtable();
  97. private Hashtable taskClassDefinitions = new Hashtable();
  98. private Hashtable targets = new Hashtable();
  99. private FilterSet globalFilterSet = new FilterSet();
  100. private FilterSetCollection globalFilters = new FilterSetCollection(globalFilterSet);
  101. private File baseDir;
  102. private Vector listeners = new Vector();
  103. /** The Ant core classloader - may be null if using system loader */
  104. private ClassLoader coreLoader = null;
  105. /** Records the latest task on a thread */
  106. private Hashtable threadTasks = new Hashtable();
  107. static {
  108. // Determine the Java version by looking at available classes
  109. // java.lang.StrictMath was introduced in JDK 1.3
  110. // java.lang.ThreadLocal was introduced in JDK 1.2
  111. // java.lang.Void was introduced in JDK 1.1
  112. // Count up version until a NoClassDefFoundError ends the try
  113. try {
  114. javaVersion = JAVA_1_0;
  115. Class.forName("java.lang.Void");
  116. javaVersion = JAVA_1_1;
  117. Class.forName("java.lang.ThreadLocal");
  118. javaVersion = JAVA_1_2;
  119. Class.forName("java.lang.StrictMath");
  120. javaVersion = JAVA_1_3;
  121. Class.forName("java.lang.CharSequence");
  122. javaVersion = JAVA_1_4;
  123. } catch (ClassNotFoundException cnfe) {
  124. // swallow as we've hit the max class version that
  125. // we have
  126. }
  127. }
  128. private FileUtils fileUtils;
  129. public Project() {
  130. fileUtils = FileUtils.newFileUtils();
  131. }
  132. /**
  133. * Initialise the project.
  134. *
  135. * This involves setting the default task definitions and loading the
  136. * system properties.
  137. */
  138. public void init() throws BuildException {
  139. setJavaVersionProperty();
  140. String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
  141. try {
  142. Properties props = new Properties();
  143. InputStream in = this.getClass().getResourceAsStream(defs);
  144. if (in == null) {
  145. throw new BuildException("Can't load default task list");
  146. }
  147. props.load(in);
  148. in.close();
  149. Enumeration enum = props.propertyNames();
  150. while (enum.hasMoreElements()) {
  151. String key = (String) enum.nextElement();
  152. String value = props.getProperty(key);
  153. try {
  154. Class taskClass = Class.forName(value);
  155. addTaskDefinition(key, taskClass);
  156. } catch (NoClassDefFoundError ncdfe) {
  157. // ignore...
  158. } catch (ClassNotFoundException cnfe) {
  159. // ignore...
  160. }
  161. }
  162. } catch (IOException ioe) {
  163. throw new BuildException("Can't load default task list");
  164. }
  165. String dataDefs = "/org/apache/tools/ant/types/defaults.properties";
  166. try{
  167. Properties props = new Properties();
  168. InputStream in = this.getClass().getResourceAsStream(dataDefs);
  169. if (in == null) {
  170. throw new BuildException("Can't load default datatype list");
  171. }
  172. props.load(in);
  173. in.close();
  174. Enumeration enum = props.propertyNames();
  175. while (enum.hasMoreElements()) {
  176. String key = (String) enum.nextElement();
  177. String value = props.getProperty(key);
  178. try {
  179. Class dataClass = Class.forName(value);
  180. addDataTypeDefinition(key, dataClass);
  181. } catch (NoClassDefFoundError ncdfe) {
  182. // ignore...
  183. } catch (ClassNotFoundException cnfe) {
  184. // ignore...
  185. }
  186. }
  187. } catch (IOException ioe) {
  188. throw new BuildException("Can't load default datatype list");
  189. }
  190. setSystemProperties();
  191. }
  192. public void setCoreLoader(ClassLoader coreLoader) {
  193. this.coreLoader = coreLoader;
  194. }
  195. public ClassLoader getCoreLoader() {
  196. return coreLoader;
  197. }
  198. public void addBuildListener(BuildListener listener) {
  199. listeners.addElement(listener);
  200. }
  201. public void removeBuildListener(BuildListener listener) {
  202. listeners.removeElement(listener);
  203. }
  204. public Vector getBuildListeners() {
  205. return listeners;
  206. }
  207. public void log(String msg) {
  208. log(msg, MSG_INFO);
  209. }
  210. public void log(String msg, int msgLevel) {
  211. fireMessageLogged(this, msg, msgLevel);
  212. }
  213. public void log(Task task, String msg, int msgLevel) {
  214. fireMessageLogged(task, msg, msgLevel);
  215. }
  216. public void log(Target target, String msg, int msgLevel) {
  217. fireMessageLogged(target, msg, msgLevel);
  218. }
  219. public FilterSet getGlobalFilterSet() {
  220. return globalFilterSet;
  221. }
  222. public void setProperty(String name, String value) {
  223. // command line properties take precedence
  224. if (null != userProperties.get(name)) {
  225. log("Override ignored for user property " + name, MSG_VERBOSE);
  226. return;
  227. }
  228. log("Setting project property: " + name + " -> " +
  229. value, MSG_DEBUG);
  230. properties.put(name, value);
  231. }
  232. public void setUserProperty(String name, String value) {
  233. log("Setting ro project property: " + name + " -> " +
  234. value, MSG_DEBUG);
  235. userProperties.put(name, value);
  236. properties.put(name, value);
  237. }
  238. public String getProperty(String name) {
  239. if (name == null) return null;
  240. String property = (String) properties.get(name);
  241. return property;
  242. }
  243. public String getUserProperty(String name) {
  244. if (name == null) return null;
  245. String property = (String) userProperties.get(name);
  246. return property;
  247. }
  248. public Hashtable getProperties() {
  249. return properties;
  250. }
  251. public Hashtable getUserProperties() {
  252. return userProperties;
  253. }
  254. public void setDefaultTarget(String defaultTarget) {
  255. this.defaultTarget = defaultTarget;
  256. }
  257. // deprecated, use setDefault
  258. public String getDefaultTarget() {
  259. return defaultTarget;
  260. }
  261. // match the attribute name
  262. public void setDefault(String defaultTarget) {
  263. this.defaultTarget = defaultTarget;
  264. }
  265. public void setName(String name) {
  266. setUserProperty("ant.project.name", name);
  267. this.name = name;
  268. }
  269. public String getName() {
  270. return name;
  271. }
  272. public void setDescription(String description) {
  273. this.description = description;
  274. }
  275. // Will return null if no description has been set
  276. public String getDescription() {
  277. return description;
  278. }
  279. /** @deprecated */
  280. public void addFilter(String token, String value) {
  281. if (token == null) {
  282. return;
  283. }
  284. globalFilterSet.addFilter(new FilterSet.Filter(token, value));
  285. }
  286. /** @deprecated */
  287. public Hashtable getFilters() {
  288. // we need to build the hashtable dynamically
  289. return globalFilterSet.getFilterHash();
  290. }
  291. // match basedir attribute in xml
  292. public void setBasedir(String baseD) throws BuildException {
  293. setBaseDir(new File(baseD));
  294. }
  295. public void setBaseDir(File baseDir) throws BuildException {
  296. baseDir = fileUtils.normalize(baseDir.getAbsolutePath());
  297. if (!baseDir.exists())
  298. throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " does not exist");
  299. if (!baseDir.isDirectory())
  300. throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " is not a directory");
  301. this.baseDir = baseDir;
  302. setProperty( "basedir", this.baseDir.getPath());
  303. String msg = "Project base dir set to: " + this.baseDir;
  304. log(msg, MSG_VERBOSE);
  305. }
  306. public File getBaseDir() {
  307. if (baseDir == null) {
  308. try {
  309. setBasedir(".");
  310. } catch (BuildException ex) {
  311. ex.printStackTrace();
  312. }
  313. }
  314. return baseDir;
  315. }
  316. public static String getJavaVersion() {
  317. return javaVersion;
  318. }
  319. public void setJavaVersionProperty() {
  320. setProperty("ant.java.version", javaVersion);
  321. // sanity check
  322. if (javaVersion == JAVA_1_0) {
  323. throw new BuildException("Ant cannot work on Java 1.0");
  324. }
  325. log("Detected Java version: " + javaVersion + " in: " + System.getProperty("java.home"), MSG_VERBOSE);
  326. log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
  327. }
  328. public void setSystemProperties() {
  329. Properties systemP = System.getProperties();
  330. Enumeration e = systemP.keys();
  331. while (e.hasMoreElements()) {
  332. Object name = e.nextElement();
  333. String value = systemP.get(name).toString();
  334. this.setProperty(name.toString(), value);
  335. }
  336. }
  337. public void addTaskDefinition(String taskName, Class taskClass) {
  338. String msg = " +User task: " + taskName + " " + taskClass.getName();
  339. log(msg, MSG_DEBUG);
  340. taskClassDefinitions.put(taskName, taskClass);
  341. }
  342. public Hashtable getTaskDefinitions() {
  343. return taskClassDefinitions;
  344. }
  345. public void addDataTypeDefinition(String typeName, Class typeClass) {
  346. String msg = " +User datatype: " + typeName + " " + typeClass.getName();
  347. log(msg, MSG_DEBUG);
  348. dataClassDefinitions.put(typeName, typeClass);
  349. }
  350. public Hashtable getDataTypeDefinitions() {
  351. return dataClassDefinitions;
  352. }
  353. /**
  354. * This call expects to add a <em>new</em> Target.
  355. * @param target is the Target to be added to the current
  356. * Project.
  357. * @exception BuildException if the Target already exists
  358. * in the project.
  359. * @see Project#addOrReplaceTarget to replace existing Targets.
  360. */
  361. public void addTarget(Target target) {
  362. String name = target.getName();
  363. if (targets.get(name) != null) {
  364. throw new BuildException("Duplicate target: `"+name+"'");
  365. }
  366. addOrReplaceTarget(name, target);
  367. }
  368. /**
  369. * This call expects to add a <em>new</em> Target.
  370. * @param target is the Target to be added to the current
  371. * Project.
  372. * @param targetName is the name to use for the Target
  373. * @exception BuildException if the Target already exists
  374. * in the project.
  375. * @see Project#addOrReplaceTarget to replace existing Targets.
  376. */
  377. public void addTarget(String targetName, Target target)
  378. throws BuildException {
  379. if (targets.get(targetName) != null) {
  380. throw new BuildException("Duplicate target: `"+targetName+"'");
  381. }
  382. addOrReplaceTarget(targetName, target);
  383. }
  384. /**
  385. * @param target is the Target to be added or replaced in
  386. * the current Project.
  387. */
  388. public void addOrReplaceTarget(Target target) {
  389. addOrReplaceTarget(target.getName(), target);
  390. }
  391. /**
  392. * @param target is the Target to be added/replaced in
  393. * the current Project.
  394. * @param targetName is the name to use for the Target
  395. */
  396. public void addOrReplaceTarget(String targetName, Target target) {
  397. String msg = " +Target: " + targetName;
  398. log(msg, MSG_DEBUG);
  399. target.setProject(this);
  400. targets.put(targetName, target);
  401. }
  402. public Hashtable getTargets() {
  403. return targets;
  404. }
  405. public Task createTask(String taskType) throws BuildException {
  406. Class c = (Class) taskClassDefinitions.get(taskType);
  407. if (c == null)
  408. return null;
  409. try {
  410. Object o = c.newInstance();
  411. Task task = null;
  412. if( o instanceof Task ) {
  413. task=(Task)o;
  414. } else {
  415. // "Generic" Bean - use the setter pattern
  416. // and an Adapter
  417. TaskAdapter taskA=new TaskAdapter();
  418. taskA.setProxy( o );
  419. task=taskA;
  420. }
  421. task.setProject(this);
  422. task.setTaskType(taskType);
  423. // set default value, can be changed by the user
  424. task.setTaskName(taskType);
  425. String msg = " +Task: " + taskType;
  426. log (msg, MSG_DEBUG);
  427. return task;
  428. } catch (Throwable t) {
  429. String msg = "Could not create task of type: "
  430. + taskType + " due to " + t;
  431. throw new BuildException(msg, t);
  432. }
  433. }
  434. public Object createDataType(String typeName) throws BuildException {
  435. Class c = (Class) dataClassDefinitions.get(typeName);
  436. if (c == null)
  437. return null;
  438. try {
  439. java.lang.reflect.Constructor ctor = null;
  440. boolean noArg = false;
  441. // DataType can have a "no arg" constructor or take a single
  442. // Project argument.
  443. try {
  444. ctor = c.getConstructor(new Class[0]);
  445. noArg = true;
  446. } catch (NoSuchMethodException nse) {
  447. ctor = c.getConstructor(new Class[] {getClass()});
  448. noArg = false;
  449. }
  450. Object o = null;
  451. if (noArg) {
  452. o = ctor.newInstance(new Object[0]);
  453. } else {
  454. o = ctor.newInstance(new Object[] {this});
  455. }
  456. if (o instanceof ProjectComponent) {
  457. ((ProjectComponent)o).setProject(this);
  458. }
  459. String msg = " +DataType: " + typeName;
  460. log (msg, MSG_DEBUG);
  461. return o;
  462. } catch (java.lang.reflect.InvocationTargetException ite) {
  463. Throwable t = ite.getTargetException();
  464. String msg = "Could not create datatype of type: "
  465. + typeName + " due to " + t;
  466. throw new BuildException(msg, t);
  467. } catch (Throwable t) {
  468. String msg = "Could not create datatype of type: "
  469. + typeName + " due to " + t;
  470. throw new BuildException(msg, t);
  471. }
  472. }
  473. public void executeTargets(Vector targetNames) throws BuildException {
  474. Throwable error = null;
  475. for (int i = 0; i < targetNames.size(); i++) {
  476. executeTarget((String)targetNames.elementAt(i));
  477. }
  478. }
  479. public void demuxOutput(String line, boolean isError) {
  480. Task task = (Task)threadTasks.get(Thread.currentThread());
  481. if (task == null) {
  482. fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO);
  483. }
  484. else {
  485. if (isError) {
  486. task.handleErrorOutput(line);
  487. }
  488. else {
  489. task.handleOutput(line);
  490. }
  491. }
  492. }
  493. public void executeTarget(String targetName) throws BuildException {
  494. // sanity check ourselves, if we've been asked to build nothing
  495. // then we should complain
  496. if (targetName == null) {
  497. String msg = "No target specified";
  498. throw new BuildException(msg);
  499. }
  500. // Sort the dependency tree, and run everything from the
  501. // beginning until we hit our targetName.
  502. // Sorting checks if all the targets (and dependencies)
  503. // exist, and if there is any cycle in the dependency
  504. // graph.
  505. Vector sortedTargets = topoSort(targetName, targets);
  506. int curidx = 0;
  507. Target curtarget;
  508. do {
  509. curtarget = (Target) sortedTargets.elementAt(curidx++);
  510. curtarget.performTasks();
  511. } while (!curtarget.getName().equals(targetName));
  512. }
  513. /**
  514. * Return the canonical form of fileName as an absolute path.
  515. *
  516. * <p>If fileName is a relative file name, resolve it relative to
  517. * rootDir.</p>
  518. *
  519. * @deprecated
  520. */
  521. public File resolveFile(String fileName, File rootDir) {
  522. return fileUtils.resolveFile(rootDir, fileName);
  523. }
  524. public File resolveFile(String fileName) {
  525. return fileUtils.resolveFile(baseDir, fileName);
  526. }
  527. /**
  528. * Translate a path into its native (platform specific) format.
  529. * <p>
  530. * This method uses the PathTokenizer class to separate the input path
  531. * into its components. This handles DOS style paths in a relatively
  532. * sensible way. The file separators are then converted to their platform
  533. * specific versions.
  534. *
  535. * @param to_process the path to be converted
  536. *
  537. * @return the native version of to_process or
  538. * an empty string if to_process is null or empty
  539. */
  540. static public String translatePath(String to_process) {
  541. if ( to_process == null || to_process.length() == 0 ) {
  542. return "";
  543. }
  544. StringBuffer path = new StringBuffer(to_process.length() + 50);
  545. PathTokenizer tokenizer = new PathTokenizer(to_process);
  546. while (tokenizer.hasMoreTokens()) {
  547. String pathComponent = tokenizer.nextToken();
  548. pathComponent = pathComponent.replace('/', File.separatorChar);
  549. pathComponent = pathComponent.replace('\\', File.separatorChar);
  550. if (path.length() != 0) {
  551. path.append(File.pathSeparatorChar);
  552. }
  553. path.append(pathComponent);
  554. }
  555. return path.toString();
  556. }
  557. /**
  558. * Convienence method to copy a file from a source to a destination.
  559. * No filtering is performed.
  560. *
  561. * @throws IOException
  562. *
  563. * @deprecated
  564. */
  565. public void copyFile(String sourceFile, String destFile) throws IOException {
  566. fileUtils.copyFile(sourceFile, destFile);
  567. }
  568. /**
  569. * Convienence method to copy a file from a source to a destination
  570. * specifying if token filtering must be used.
  571. *
  572. * @throws IOException
  573. *
  574. * @deprecated
  575. */
  576. public void copyFile(String sourceFile, String destFile, boolean filtering)
  577. throws IOException {
  578. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null);
  579. }
  580. /**
  581. * Convienence method to copy a file from a source to a
  582. * destination specifying if token filtering must be used and if
  583. * source files may overwrite newer destination files.
  584. *
  585. * @throws IOException
  586. *
  587. * @deprecated
  588. */
  589. public void copyFile(String sourceFile, String destFile, boolean filtering,
  590. boolean overwrite) throws IOException {
  591. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite);
  592. }
  593. /**
  594. * Convienence method to copy a file from a source to a
  595. * destination specifying if token filtering must be used, if
  596. * source files may overwrite newer destination files and the
  597. * last modified time of <code>destFile</code> file should be made equal
  598. * to the last modified time of <code>sourceFile</code>.
  599. *
  600. * @throws IOException
  601. *
  602. * @deprecated
  603. */
  604. public void copyFile(String sourceFile, String destFile, boolean filtering,
  605. boolean overwrite, boolean preserveLastModified)
  606. throws IOException {
  607. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null,
  608. overwrite, preserveLastModified);
  609. }
  610. /**
  611. * Convienence method to copy a file from a source to a destination.
  612. * No filtering is performed.
  613. *
  614. * @throws IOException
  615. *
  616. * @deprecated
  617. */
  618. public void copyFile(File sourceFile, File destFile) throws IOException {
  619. fileUtils.copyFile(sourceFile, destFile);
  620. }
  621. /**
  622. * Convienence method to copy a file from a source to a destination
  623. * specifying if token filtering must be used.
  624. *
  625. * @throws IOException
  626. *
  627. * @deprecated
  628. */
  629. public void copyFile(File sourceFile, File destFile, boolean filtering)
  630. throws IOException {
  631. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null);
  632. }
  633. /**
  634. * Convienence method to copy a file from a source to a
  635. * destination specifying if token filtering must be used and if
  636. * source files may overwrite newer destination files.
  637. *
  638. * @throws IOException
  639. *
  640. * @deprecated
  641. */
  642. public void copyFile(File sourceFile, File destFile, boolean filtering,
  643. boolean overwrite) throws IOException {
  644. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite);
  645. }
  646. /**
  647. * Convienence method to copy a file from a source to a
  648. * destination specifying if token filtering must be used, if
  649. * source files may overwrite newer destination files and the
  650. * last modified time of <code>destFile</code> file should be made equal
  651. * to the last modified time of <code>sourceFile</code>.
  652. *
  653. * @throws IOException
  654. *
  655. * @deprecated
  656. */
  657. public void copyFile(File sourceFile, File destFile, boolean filtering,
  658. boolean overwrite, boolean preserveLastModified)
  659. throws IOException {
  660. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null,
  661. overwrite, preserveLastModified);
  662. }
  663. /**
  664. * Calls File.setLastModified(long time) in a Java 1.1 compatible way.
  665. *
  666. * @deprecated
  667. */
  668. public void setFileLastModified(File file, long time) throws BuildException {
  669. if (getJavaVersion() == JAVA_1_1) {
  670. log("Cannot change the modification time of " + file
  671. + " in JDK 1.1", Project.MSG_WARN);
  672. return;
  673. }
  674. fileUtils.setFileLastModified(file, time);
  675. log("Setting modification time for " + file, MSG_VERBOSE);
  676. }
  677. /**
  678. * returns the boolean equivalent of a string, which is considered true
  679. * if either "on", "true", or "yes" is found, ignoring case.
  680. */
  681. public static boolean toBoolean(String s) {
  682. return (s.equalsIgnoreCase("on") ||
  683. s.equalsIgnoreCase("true") ||
  684. s.equalsIgnoreCase("yes"));
  685. }
  686. /**
  687. * Topologically sort a set of Targets.
  688. * @param root is the (String) name of the root Target. The sort is
  689. * created in such a way that the sequence of Targets uptil the root
  690. * target is the minimum possible such sequence.
  691. * @param targets is a Hashtable representing a "name to Target" mapping
  692. * @return a Vector of Strings with the names of the targets in
  693. * sorted order.
  694. * @exception BuildException if there is a cyclic dependency among the
  695. * Targets, or if a Target does not exist.
  696. */
  697. public final Vector topoSort(String root, Hashtable targets)
  698. throws BuildException {
  699. Vector ret = new Vector();
  700. Hashtable state = new Hashtable();
  701. Stack visiting = new Stack();
  702. // We first run a DFS based sort using the root as the starting node.
  703. // This creates the minimum sequence of Targets to the root node.
  704. // We then do a sort on any remaining unVISITED targets.
  705. // This is unnecessary for doing our build, but it catches
  706. // circular dependencies or missing Targets on the entire
  707. // dependency tree, not just on the Targets that depend on the
  708. // build Target.
  709. tsort(root, targets, state, visiting, ret);
  710. log("Build sequence for target `"+root+"' is "+ret, MSG_VERBOSE);
  711. for (Enumeration en=targets.keys(); en.hasMoreElements();) {
  712. String curTarget = (String)(en.nextElement());
  713. String st = (String) state.get(curTarget);
  714. if (st == null) {
  715. tsort(curTarget, targets, state, visiting, ret);
  716. }
  717. else if (st == VISITING) {
  718. throw new RuntimeException("Unexpected node in visiting state: "+curTarget);
  719. }
  720. }
  721. log("Complete build sequence is "+ret, MSG_VERBOSE);
  722. return ret;
  723. }
  724. // one step in a recursive DFS traversal of the Target dependency tree.
  725. // - The Hashtable "state" contains the state (VISITED or VISITING or null)
  726. // of all the target names.
  727. // - The Stack "visiting" contains a stack of target names that are
  728. // currently on the DFS stack. (NB: the target names in "visiting" are
  729. // exactly the target names in "state" that are in the VISITING state.)
  730. // 1. Set the current target to the VISITING state, and push it onto
  731. // the "visiting" stack.
  732. // 2. Throw a BuildException if any child of the current node is
  733. // in the VISITING state (implies there is a cycle.) It uses the
  734. // "visiting" Stack to construct the cycle.
  735. // 3. If any children have not been VISITED, tsort() the child.
  736. // 4. Add the current target to the Vector "ret" after the children
  737. // have been visited. Move the current target to the VISITED state.
  738. // "ret" now contains the sorted sequence of Targets upto the current
  739. // Target.
  740. private final void tsort(String root, Hashtable targets,
  741. Hashtable state, Stack visiting,
  742. Vector ret)
  743. throws BuildException {
  744. state.put(root, VISITING);
  745. visiting.push(root);
  746. Target target = (Target)(targets.get(root));
  747. // Make sure we exist
  748. if (target == null) {
  749. StringBuffer sb = new StringBuffer("Target `");
  750. sb.append(root);
  751. sb.append("' does not exist in this project. ");
  752. visiting.pop();
  753. if (!visiting.empty()) {
  754. String parent = (String)visiting.peek();
  755. sb.append("It is used from target `");
  756. sb.append(parent);
  757. sb.append("'.");
  758. }
  759. throw new BuildException(new String(sb));
  760. }
  761. for (Enumeration en=target.getDependencies(); en.hasMoreElements();) {
  762. String cur = (String) en.nextElement();
  763. String m=(String)state.get(cur);
  764. if (m == null) {
  765. // Not been visited
  766. tsort(cur, targets, state, visiting, ret);
  767. }
  768. else if (m == VISITING) {
  769. // Currently visiting this node, so have a cycle
  770. throw makeCircularException(cur, visiting);
  771. }
  772. }
  773. String p = (String) visiting.pop();
  774. if (root != p) {
  775. throw new RuntimeException("Unexpected internal error: expected to pop "+root+" but got "+p);
  776. }
  777. state.put(root, VISITED);
  778. ret.addElement(target);
  779. }
  780. private static BuildException makeCircularException(String end, Stack stk) {
  781. StringBuffer sb = new StringBuffer("Circular dependency: ");
  782. sb.append(end);
  783. String c;
  784. do {
  785. c = (String)stk.pop();
  786. sb.append(" <- ");
  787. sb.append(c);
  788. } while(!c.equals(end));
  789. return new BuildException(new String(sb));
  790. }
  791. public void addReference(String name, Object value) {
  792. if (null != references.get(name)) {
  793. log("Overriding previous definition of reference to " + name,
  794. MSG_WARN);
  795. }
  796. log("Adding reference: " + name + " -> " + value, MSG_DEBUG);
  797. references.put(name,value);
  798. }
  799. public Hashtable getReferences() {
  800. return references;
  801. }
  802. protected void fireBuildStarted() {
  803. BuildEvent event = new BuildEvent(this);
  804. for (int i = 0; i < listeners.size(); i++) {
  805. BuildListener listener = (BuildListener) listeners.elementAt(i);
  806. listener.buildStarted(event);
  807. }
  808. }
  809. protected void fireBuildFinished(Throwable exception) {
  810. BuildEvent event = new BuildEvent(this);
  811. event.setException(exception);
  812. for (int i = 0; i < listeners.size(); i++) {
  813. BuildListener listener = (BuildListener) listeners.elementAt(i);
  814. listener.buildFinished(event);
  815. }
  816. }
  817. protected void fireTargetStarted(Target target) {
  818. BuildEvent event = new BuildEvent(target);
  819. for (int i = 0; i < listeners.size(); i++) {
  820. BuildListener listener = (BuildListener) listeners.elementAt(i);
  821. listener.targetStarted(event);
  822. }
  823. }
  824. protected void fireTargetFinished(Target target, Throwable exception) {
  825. BuildEvent event = new BuildEvent(target);
  826. event.setException(exception);
  827. for (int i = 0; i < listeners.size(); i++) {
  828. BuildListener listener = (BuildListener) listeners.elementAt(i);
  829. listener.targetFinished(event);
  830. }
  831. }
  832. protected void fireTaskStarted(Task task) {
  833. // register this as the current task on the current thread.
  834. threadTasks.put(Thread.currentThread(), task);
  835. BuildEvent event = new BuildEvent(task);
  836. for (int i = 0; i < listeners.size(); i++) {
  837. BuildListener listener = (BuildListener) listeners.elementAt(i);
  838. listener.taskStarted(event);
  839. }
  840. }
  841. protected void fireTaskFinished(Task task, Throwable exception) {
  842. threadTasks.remove(Thread.currentThread());
  843. System.out.flush();
  844. System.err.flush();
  845. BuildEvent event = new BuildEvent(task);
  846. event.setException(exception);
  847. for (int i = 0; i < listeners.size(); i++) {
  848. BuildListener listener = (BuildListener) listeners.elementAt(i);
  849. listener.taskFinished(event);
  850. }
  851. }
  852. private void fireMessageLoggedEvent(BuildEvent event, String message, int priority) {
  853. event.setMessage(message, priority);
  854. for (int i = 0; i < listeners.size(); i++) {
  855. BuildListener listener = (BuildListener) listeners.elementAt(i);
  856. listener.messageLogged(event);
  857. }
  858. }
  859. protected void fireMessageLogged(Project project, String message, int priority) {
  860. BuildEvent event = new BuildEvent(project);
  861. fireMessageLoggedEvent(event, message, priority);
  862. }
  863. protected void fireMessageLogged(Target target, String message, int priority) {
  864. BuildEvent event = new BuildEvent(target);
  865. fireMessageLoggedEvent(event, message, priority);
  866. }
  867. protected void fireMessageLogged(Task task, String message, int priority) {
  868. BuildEvent event = new BuildEvent(task);
  869. fireMessageLoggedEvent(event, message, priority);
  870. }
  871. }