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.

Main.java 41 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  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;
  19. import java.io.File;
  20. import java.io.FileInputStream;
  21. import java.io.FileOutputStream;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.PrintStream;
  25. import java.util.Enumeration;
  26. import java.util.Properties;
  27. import java.util.Vector;
  28. import java.util.HashMap;
  29. import org.apache.tools.ant.input.DefaultInputHandler;
  30. import org.apache.tools.ant.input.InputHandler;
  31. import org.apache.tools.ant.launch.AntMain;
  32. import org.apache.tools.ant.util.ClasspathUtils;
  33. import org.apache.tools.ant.util.FileUtils;
  34. import org.apache.tools.ant.util.ProxySetup;
  35. /**
  36. * Command line entry point into Ant. This class is entered via the
  37. * canonical `public static void main` entry point and reads the
  38. * command line arguments. It then assembles and executes an Ant
  39. * project.
  40. * <p>
  41. * If you integrating Ant into some other tool, this is not the class
  42. * to use as an entry point. Please see the source code of this
  43. * class to see how it manipulates the Ant project classes.
  44. *
  45. */
  46. public class Main implements AntMain {
  47. /** The default build file name. {@value} */
  48. public static final String DEFAULT_BUILD_FILENAME = "build.xml";
  49. /** Our current message output status. Follows Project.MSG_XXX. */
  50. private int msgOutputLevel = Project.MSG_INFO;
  51. /** File that we are using for configuration. */
  52. private File buildFile; /* null */
  53. /** Stream to use for logging. */
  54. private static PrintStream out = System.out;
  55. /** Stream that we are using for logging error messages. */
  56. private static PrintStream err = System.err;
  57. /** The build targets. */
  58. private Vector targets = new Vector();
  59. /** Set of properties that can be used by tasks. */
  60. private Properties definedProps = new Properties();
  61. /** Names of classes to add as listeners to project. */
  62. private Vector listeners = new Vector(1);
  63. /** File names of property files to load on startup. */
  64. private Vector propertyFiles = new Vector(1);
  65. /** Indicates whether this build is to support interactive input */
  66. private boolean allowInput = true;
  67. /** keep going mode */
  68. private boolean keepGoingMode = false;
  69. /**
  70. * The Ant logger class. There may be only one logger. It will have
  71. * the right to use the 'out' PrintStream. The class must implements the
  72. * BuildLogger interface.
  73. */
  74. private String loggerClassname = null;
  75. /**
  76. * The Ant InputHandler class. There may be only one input
  77. * handler.
  78. */
  79. private String inputHandlerClassname = null;
  80. /**
  81. * Whether or not output to the log is to be unadorned.
  82. */
  83. private boolean emacsMode = false;
  84. /**
  85. * Whether or not this instance has successfully been
  86. * constructed and is ready to run.
  87. */
  88. private boolean readyToRun = false;
  89. /**
  90. * Whether or not we should only parse and display the project help
  91. * information.
  92. */
  93. private boolean projectHelp = false;
  94. /**
  95. * Whether or not a logfile is being used. This is used to
  96. * check if the output streams must be closed.
  97. */
  98. private static boolean isLogFileUsed = false;
  99. /**
  100. * optional thread priority
  101. */
  102. private Integer threadPriority = null;
  103. /**
  104. * proxy flag: default is true
  105. */
  106. private boolean proxy = true;
  107. /**
  108. * Prints the message of the Throwable if it (the message) is not
  109. * <code>null</code>.
  110. *
  111. * @param t Throwable to print the message of.
  112. * Must not be <code>null</code>.
  113. */
  114. private static void printMessage(Throwable t) {
  115. String message = t.getMessage();
  116. if (message != null) {
  117. System.err.println(message);
  118. }
  119. }
  120. /**
  121. * Creates a new instance of this class using the
  122. * arguments specified, gives it any extra user properties which have been
  123. * specified, and then runs the build using the classloader provided.
  124. *
  125. * @param args Command line arguments. Must not be <code>null</code>.
  126. * @param additionalUserProperties Any extra properties to use in this
  127. * build. May be <code>null</code>, which is the equivalent to
  128. * passing in an empty set of properties.
  129. * @param coreLoader Classloader used for core classes. May be
  130. * <code>null</code> in which case the system classloader is used.
  131. */
  132. public static void start(String[] args, Properties additionalUserProperties,
  133. ClassLoader coreLoader) {
  134. Main m = new Main();
  135. m.startAnt(args, additionalUserProperties, coreLoader);
  136. }
  137. /**
  138. * Start Ant
  139. * @param args command line args
  140. * @param additionalUserProperties properties to set beyond those that
  141. * may be specified on the args list
  142. * @param coreLoader - not used
  143. *
  144. * @since Ant 1.6
  145. */
  146. public void startAnt(String[] args, Properties additionalUserProperties,
  147. ClassLoader coreLoader) {
  148. try {
  149. Diagnostics.validateVersion();
  150. processArgs(args);
  151. } catch (Throwable exc) {
  152. handleLogfile();
  153. printMessage(exc);
  154. exit(1);
  155. return;
  156. }
  157. if (additionalUserProperties != null) {
  158. for (Enumeration e = additionalUserProperties.keys();
  159. e.hasMoreElements();) {
  160. String key = (String) e.nextElement();
  161. String property = additionalUserProperties.getProperty(key);
  162. definedProps.put(key, property);
  163. }
  164. }
  165. // expect the worst
  166. int exitCode = 1;
  167. try {
  168. try {
  169. runBuild(coreLoader);
  170. exitCode = 0;
  171. } catch (ExitStatusException ese) {
  172. exitCode = ese.getStatus();
  173. if (exitCode != 0) {
  174. throw ese;
  175. }
  176. }
  177. } catch (BuildException be) {
  178. if (err != System.err) {
  179. printMessage(be);
  180. }
  181. } catch (Throwable exc) {
  182. exc.printStackTrace();
  183. printMessage(exc);
  184. } finally {
  185. handleLogfile();
  186. }
  187. exit(exitCode);
  188. }
  189. /**
  190. * This operation is expected to call {@link System#exit(int)}, which
  191. * is what the base version does.
  192. * However, it is possible to do something else.
  193. * @param exitCode code to exit with
  194. */
  195. protected void exit(int exitCode) {
  196. System.exit(exitCode);
  197. }
  198. /**
  199. * Close logfiles, if we have been writing to them.
  200. *
  201. * @since Ant 1.6
  202. */
  203. private static void handleLogfile() {
  204. if (isLogFileUsed) {
  205. FileUtils.close(out);
  206. FileUtils.close(err);
  207. }
  208. }
  209. /**
  210. * Command line entry point. This method kicks off the building
  211. * of a project object and executes a build using either a given
  212. * target or the default target.
  213. *
  214. * @param args Command line arguments. Must not be <code>null</code>.
  215. */
  216. public static void main(String[] args) {
  217. start(args, null, null);
  218. }
  219. /**
  220. * Constructor used when creating Main for later arg processing
  221. * and startup
  222. */
  223. public Main() {
  224. }
  225. /**
  226. * Sole constructor, which parses and deals with command line
  227. * arguments.
  228. *
  229. * @param args Command line arguments. Must not be <code>null</code>.
  230. *
  231. * @exception BuildException if the specified build file doesn't exist
  232. * or is a directory.
  233. *
  234. * @deprecated since 1.6.x
  235. */
  236. protected Main(String[] args) throws BuildException {
  237. processArgs(args);
  238. }
  239. /**
  240. * Process command line arguments.
  241. * When ant is started from Launcher, launcher-only arguments doe not get
  242. * passed through to this routine.
  243. *
  244. * @param args the command line arguments.
  245. *
  246. * @since Ant 1.6
  247. */
  248. private void processArgs(String[] args) {
  249. String searchForThis = null;
  250. PrintStream logTo = null;
  251. //this is hte list of lu
  252. HashMap launchCommands =new HashMap();
  253. launchCommands.put("-lib","");
  254. launchCommands.put("-cp", "");
  255. launchCommands.put("-noclasspath", "");
  256. launchCommands.put("--noclasspath", "");
  257. launchCommands.put("-nouserlib", "");
  258. launchCommands.put("--nouserlib", "");
  259. launchCommands.put("-main", "");
  260. // cycle through given args
  261. for (int i = 0; i < args.length; i++) {
  262. String arg = args[i];
  263. if (arg.equals("-help") || arg.equals("-h")) {
  264. printUsage();
  265. return;
  266. } else if (arg.equals("-version")) {
  267. printVersion();
  268. return;
  269. } else if (arg.equals("-diagnostics")) {
  270. Diagnostics.doReport(System.out);
  271. return;
  272. } else if (arg.equals("-quiet") || arg.equals("-q")) {
  273. msgOutputLevel = Project.MSG_WARN;
  274. } else if (arg.equals("-verbose") || arg.equals("-v")) {
  275. printVersion();
  276. msgOutputLevel = Project.MSG_VERBOSE;
  277. } else if (arg.equals("-debug") || arg.equals("-d")) {
  278. printVersion();
  279. msgOutputLevel = Project.MSG_DEBUG;
  280. } else if (arg.equals("-noinput")) {
  281. allowInput = false;
  282. } else if (arg.equals("-logfile") || arg.equals("-l")) {
  283. try {
  284. File logFile = new File(args[i + 1]);
  285. i++;
  286. logTo = new PrintStream(new FileOutputStream(logFile));
  287. isLogFileUsed = true;
  288. } catch (IOException ioe) {
  289. String msg = "Cannot write on the specified log file. "
  290. + "Make sure the path exists and you have write "
  291. + "permissions.";
  292. throw new BuildException(msg);
  293. } catch (ArrayIndexOutOfBoundsException aioobe) {
  294. String msg = "You must specify a log file when "
  295. + "using the -log argument";
  296. throw new BuildException(msg);
  297. }
  298. } else if (arg.equals("-buildfile") || arg.equals("-file")
  299. || arg.equals("-f")) {
  300. try {
  301. buildFile = new File(args[i + 1].replace('/', File.separatorChar));
  302. i++;
  303. } catch (ArrayIndexOutOfBoundsException aioobe) {
  304. String msg = "You must specify a buildfile when "
  305. + "using the -buildfile argument";
  306. throw new BuildException(msg);
  307. }
  308. } else if (arg.equals("-listener")) {
  309. try {
  310. listeners.addElement(args[i + 1]);
  311. i++;
  312. } catch (ArrayIndexOutOfBoundsException aioobe) {
  313. String msg = "You must specify a classname when "
  314. + "using the -listener argument";
  315. throw new BuildException(msg);
  316. }
  317. } else if (arg.startsWith("-D")) {
  318. /* Interestingly enough, we get to here when a user
  319. * uses -Dname=value. However, in some cases, the OS
  320. * goes ahead and parses this out to args
  321. * {"-Dname", "value"}
  322. * so instead of parsing on "=", we just make the "-D"
  323. * characters go away and skip one argument forward.
  324. *
  325. * I don't know how to predict when the JDK is going
  326. * to help or not, so we simply look for the equals sign.
  327. */
  328. String name = arg.substring(2, arg.length());
  329. String value = null;
  330. int posEq = name.indexOf("=");
  331. if (posEq > 0) {
  332. value = name.substring(posEq + 1);
  333. name = name.substring(0, posEq);
  334. } else if (i < args.length - 1) {
  335. value = args[++i];
  336. } else {
  337. throw new BuildException("Missing value for property "
  338. + name);
  339. }
  340. definedProps.put(name, value);
  341. } else if (arg.equals("-logger")) {
  342. if (loggerClassname != null) {
  343. throw new BuildException("Only one logger class may "
  344. + " be specified.");
  345. }
  346. try {
  347. loggerClassname = args[++i];
  348. } catch (ArrayIndexOutOfBoundsException aioobe) {
  349. throw new BuildException("You must specify a classname when"
  350. + " using the -logger argument");
  351. }
  352. } else if (arg.equals("-inputhandler")) {
  353. if (inputHandlerClassname != null) {
  354. throw new BuildException("Only one input handler class may "
  355. + "be specified.");
  356. }
  357. try {
  358. inputHandlerClassname = args[++i];
  359. } catch (ArrayIndexOutOfBoundsException aioobe) {
  360. throw new BuildException("You must specify a classname when"
  361. + " using the -inputhandler"
  362. + " argument");
  363. }
  364. } else if (arg.equals("-emacs") || arg.equals("-e")) {
  365. emacsMode = true;
  366. } else if (arg.equals("-projecthelp") || arg.equals("-p")) {
  367. // set the flag to display the targets and quit
  368. projectHelp = true;
  369. } else if (arg.equals("-find") || arg.equals("-s")) {
  370. // eat up next arg if present, default to build.xml
  371. if (i < args.length - 1) {
  372. searchForThis = args[++i];
  373. } else {
  374. searchForThis = DEFAULT_BUILD_FILENAME;
  375. }
  376. } else if (arg.startsWith("-propertyfile")) {
  377. try {
  378. propertyFiles.addElement(args[i + 1]);
  379. i++;
  380. } catch (ArrayIndexOutOfBoundsException aioobe) {
  381. String msg = "You must specify a property filename when "
  382. + "using the -propertyfile argument";
  383. throw new BuildException(msg);
  384. }
  385. } else if (arg.equals("-k") || arg.equals("-keep-going")) {
  386. keepGoingMode = true;
  387. } else if (arg.equals("-nice")) {
  388. try {
  389. threadPriority = Integer.decode(args[i + 1]);
  390. } catch (ArrayIndexOutOfBoundsException aioobe) {
  391. throw new BuildException(
  392. "You must supply a niceness value (1-10)"
  393. + " after the -nice option");
  394. } catch (NumberFormatException e) {
  395. throw new BuildException("Unrecognized niceness value: "
  396. + args[i + 1]);
  397. }
  398. i++;
  399. if (threadPriority.intValue() < Thread.MIN_PRIORITY
  400. || threadPriority.intValue() > Thread.MAX_PRIORITY) {
  401. throw new BuildException(
  402. "Niceness value is out of the range 1-10");
  403. }
  404. } else if (launchCommands.get(arg)!=null) {
  405. //catch script/ant mismatch with a meaningful message
  406. //we could ignore it, but there are likely to be other
  407. //version problems, so we stamp down on the configuration now
  408. String msg = "Ant's Main method is being handed "
  409. + "an option " + arg + " that is only for the launcher class."
  410. + "\nThis can be caused by a version mismatch between "
  411. + "the ant script/.bat file and Ant itself.";
  412. throw new BuildException(msg);
  413. } else if (arg.equals("-noproxy")) {
  414. proxy = false;
  415. } else if (arg.startsWith("-")) {
  416. // we don't have any more args to recognize!
  417. String msg = "Unknown argument: " + arg;
  418. System.err.println(msg);
  419. printUsage();
  420. throw new BuildException("");
  421. } else {
  422. // if it's no other arg, it may be the target
  423. targets.addElement(arg);
  424. }
  425. }
  426. // if buildFile was not specified on the command line,
  427. if (buildFile == null) {
  428. // but -find then search for it
  429. if (searchForThis != null) {
  430. buildFile = findBuildFile(System.getProperty("user.dir"),
  431. searchForThis);
  432. } else {
  433. buildFile = new File(DEFAULT_BUILD_FILENAME);
  434. }
  435. }
  436. // make sure buildfile exists
  437. if (!buildFile.exists()) {
  438. System.out.println("Buildfile: " + buildFile + " does not exist!");
  439. throw new BuildException("Build failed");
  440. }
  441. // make sure it's not a directory (this falls into the ultra
  442. // paranoid lets check everything category
  443. if (buildFile.isDirectory()) {
  444. System.out.println("What? Buildfile: " + buildFile + " is a dir!");
  445. throw new BuildException("Build failed");
  446. }
  447. // Load the property files specified by -propertyfile
  448. for (int propertyFileIndex = 0;
  449. propertyFileIndex < propertyFiles.size();
  450. propertyFileIndex++) {
  451. String filename
  452. = (String) propertyFiles.elementAt(propertyFileIndex);
  453. Properties props = new Properties();
  454. FileInputStream fis = null;
  455. try {
  456. fis = new FileInputStream(filename);
  457. props.load(fis);
  458. } catch (IOException e) {
  459. System.out.println("Could not load property file "
  460. + filename + ": " + e.getMessage());
  461. } finally {
  462. FileUtils.close(fis);
  463. }
  464. // ensure that -D properties take precedence
  465. Enumeration propertyNames = props.propertyNames();
  466. while (propertyNames.hasMoreElements()) {
  467. String name = (String) propertyNames.nextElement();
  468. if (definedProps.getProperty(name) == null) {
  469. definedProps.put(name, props.getProperty(name));
  470. }
  471. }
  472. }
  473. if (msgOutputLevel >= Project.MSG_INFO) {
  474. System.out.println("Buildfile: " + buildFile);
  475. }
  476. if (logTo != null) {
  477. out = logTo;
  478. err = logTo;
  479. System.setOut(out);
  480. System.setErr(err);
  481. }
  482. readyToRun = true;
  483. }
  484. /**
  485. * Helper to get the parent file for a given file.
  486. * <p>
  487. * Added to simulate File.getParentFile() from JDK 1.2.
  488. * @deprecated since 1.6.x
  489. *
  490. * @param file File to find parent of. Must not be <code>null</code>.
  491. * @return Parent file or null if none
  492. */
  493. private File getParentFile(File file) {
  494. File parent = file.getParentFile();
  495. if (parent != null && msgOutputLevel >= Project.MSG_VERBOSE) {
  496. System.out.println("Searching in " + parent.getAbsolutePath());
  497. }
  498. return parent;
  499. }
  500. /**
  501. * Search parent directories for the build file.
  502. * <p>
  503. * Takes the given target as a suffix to append to each
  504. * parent directory in search of a build file. Once the
  505. * root of the file-system has been reached an exception
  506. * is thrown.
  507. *
  508. * @param start Leaf directory of search.
  509. * Must not be <code>null</code>.
  510. * @param suffix Suffix filename to look for in parents.
  511. * Must not be <code>null</code>.
  512. *
  513. * @return A handle to the build file if one is found
  514. *
  515. * @exception BuildException if no build file is found
  516. */
  517. private File findBuildFile(String start, String suffix)
  518. throws BuildException {
  519. if (msgOutputLevel >= Project.MSG_INFO) {
  520. System.out.println("Searching for " + suffix + " ...");
  521. }
  522. File parent = new File(new File(start).getAbsolutePath());
  523. File file = new File(parent, suffix);
  524. // check if the target file exists in the current directory
  525. while (!file.exists()) {
  526. // change to parent directory
  527. parent = getParentFile(parent);
  528. // if parent is null, then we are at the root of the fs,
  529. // complain that we can't find the build file.
  530. if (parent == null) {
  531. throw new BuildException("Could not locate a build file!");
  532. }
  533. // refresh our file handle
  534. file = new File(parent, suffix);
  535. }
  536. return file;
  537. }
  538. /**
  539. * Executes the build. If the constructor for this instance failed
  540. * (e.g. returned after issuing a warning), this method returns
  541. * immediately.
  542. *
  543. * @param coreLoader The classloader to use to find core classes.
  544. * May be <code>null</code>, in which case the
  545. * system classloader is used.
  546. *
  547. * @exception BuildException if the build fails
  548. */
  549. private void runBuild(ClassLoader coreLoader) throws BuildException {
  550. if (!readyToRun) {
  551. return;
  552. }
  553. final Project project = new Project();
  554. project.setCoreLoader(coreLoader);
  555. Throwable error = null;
  556. try {
  557. addBuildListeners(project);
  558. addInputHandler(project);
  559. PrintStream savedErr = System.err;
  560. PrintStream savedOut = System.out;
  561. InputStream savedIn = System.in;
  562. // use a system manager that prevents from System.exit()
  563. SecurityManager oldsm = null;
  564. oldsm = System.getSecurityManager();
  565. //SecurityManager can not be installed here for backwards
  566. //compatibility reasons (PD). Needs to be loaded prior to
  567. //ant class if we are going to implement it.
  568. //System.setSecurityManager(new NoExitSecurityManager());
  569. try {
  570. if (allowInput) {
  571. project.setDefaultInputStream(System.in);
  572. }
  573. System.setIn(new DemuxInputStream(project));
  574. System.setOut(new PrintStream(new DemuxOutputStream(project, false)));
  575. System.setErr(new PrintStream(new DemuxOutputStream(project, true)));
  576. if (!projectHelp) {
  577. project.fireBuildStarted();
  578. }
  579. // set the thread priorities
  580. if (threadPriority != null) {
  581. try {
  582. project.log("Setting Ant's thread priority to "
  583. + threadPriority, Project.MSG_VERBOSE);
  584. Thread.currentThread().setPriority(threadPriority.intValue());
  585. } catch (SecurityException swallowed) {
  586. //we cannot set the priority here.
  587. project.log("A security manager refused to set the -nice value");
  588. }
  589. }
  590. project.init();
  591. // set user-define properties
  592. Enumeration e = definedProps.keys();
  593. while (e.hasMoreElements()) {
  594. String arg = (String) e.nextElement();
  595. String value = (String) definedProps.get(arg);
  596. project.setUserProperty(arg, value);
  597. }
  598. project.setUserProperty(MagicNames.ANT_FILE,
  599. buildFile.getAbsolutePath());
  600. project.setKeepGoingMode(keepGoingMode);
  601. if (proxy) {
  602. //proxy setup if enabled
  603. ProxySetup proxySetup = new ProxySetup(project);
  604. proxySetup.enableProxies();
  605. }
  606. ProjectHelper.configureProject(project, buildFile);
  607. if (projectHelp) {
  608. printDescription(project);
  609. printTargets(project, msgOutputLevel > Project.MSG_INFO);
  610. return;
  611. }
  612. // make sure that we have a target to execute
  613. if (targets.size() == 0) {
  614. if (project.getDefaultTarget() != null) {
  615. targets.addElement(project.getDefaultTarget());
  616. }
  617. }
  618. project.executeTargets(targets);
  619. } finally {
  620. // put back the original security manager
  621. //The following will never eval to true. (PD)
  622. if (oldsm != null) {
  623. System.setSecurityManager(oldsm);
  624. }
  625. System.setOut(savedOut);
  626. System.setErr(savedErr);
  627. System.setIn(savedIn);
  628. }
  629. } catch (RuntimeException exc) {
  630. error = exc;
  631. throw exc;
  632. } catch (Error e) {
  633. error = e;
  634. throw e;
  635. } finally {
  636. if (!projectHelp) {
  637. project.fireBuildFinished(error);
  638. } else if (error != null) {
  639. project.log(error.toString(), Project.MSG_ERR);
  640. }
  641. }
  642. }
  643. /**
  644. * Adds the listeners specified in the command line arguments,
  645. * along with the default listener, to the specified project.
  646. *
  647. * @param project The project to add listeners to.
  648. * Must not be <code>null</code>.
  649. */
  650. protected void addBuildListeners(Project project) {
  651. // Add the default listener
  652. project.addBuildListener(createLogger());
  653. for (int i = 0; i < listeners.size(); i++) {
  654. String className = (String) listeners.elementAt(i);
  655. BuildListener listener =
  656. (BuildListener) ClasspathUtils.newInstance(className,
  657. Main.class.getClassLoader(), BuildListener.class);
  658. if (project != null) {
  659. project.setProjectReference(listener);
  660. }
  661. project.addBuildListener(listener);
  662. }
  663. }
  664. /**
  665. * Creates the InputHandler and adds it to the project.
  666. *
  667. * @param project the project instance.
  668. *
  669. * @exception BuildException if a specified InputHandler
  670. * implementation could not be loaded.
  671. */
  672. private void addInputHandler(Project project) throws BuildException {
  673. InputHandler handler = null;
  674. if (inputHandlerClassname == null) {
  675. handler = new DefaultInputHandler();
  676. } else {
  677. handler = (InputHandler) ClasspathUtils.newInstance(
  678. inputHandlerClassname, Main.class.getClassLoader(),
  679. InputHandler.class);
  680. if (project != null) {
  681. project.setProjectReference(handler);
  682. }
  683. }
  684. project.setInputHandler(handler);
  685. }
  686. // XXX: (Jon Skeet) Any reason for writing a message and then using a bare
  687. // RuntimeException rather than just using a BuildException here? Is it
  688. // in case the message could end up being written to no loggers (as the
  689. // loggers could have failed to be created due to this failure)?
  690. /**
  691. * Creates the default build logger for sending build events to the ant
  692. * log.
  693. *
  694. * @return the logger instance for this build.
  695. */
  696. private BuildLogger createLogger() {
  697. BuildLogger logger = null;
  698. if (loggerClassname != null) {
  699. try {
  700. logger = (BuildLogger) ClasspathUtils.newInstance(
  701. loggerClassname, Main.class.getClassLoader(),
  702. BuildLogger.class);
  703. } catch (BuildException e) {
  704. System.err.println("The specified logger class "
  705. + loggerClassname
  706. + " could not be used because " + e.getMessage());
  707. throw new RuntimeException();
  708. }
  709. } else {
  710. logger = new DefaultLogger();
  711. }
  712. logger.setMessageOutputLevel(msgOutputLevel);
  713. logger.setOutputPrintStream(out);
  714. logger.setErrorPrintStream(err);
  715. logger.setEmacsMode(emacsMode);
  716. return logger;
  717. }
  718. /**
  719. * Prints the usage information for this class to <code>System.out</code>.
  720. */
  721. private static void printUsage() {
  722. String lSep = System.getProperty("line.separator");
  723. StringBuffer msg = new StringBuffer();
  724. msg.append("ant [options] [target [target2 [target3] ...]]" + lSep);
  725. msg.append("Options: " + lSep);
  726. msg.append(" -help, -h print this message" + lSep);
  727. msg.append(" -projecthelp, -p print project help information" + lSep);
  728. msg.append(" -version print the version information and exit" + lSep);
  729. msg.append(" -diagnostics print information that might be helpful to" + lSep);
  730. msg.append(" diagnose or report problems." + lSep);
  731. msg.append(" -quiet, -q be extra quiet" + lSep);
  732. msg.append(" -verbose, -v be extra verbose" + lSep);
  733. msg.append(" -debug, -d print debugging information" + lSep);
  734. msg.append(" -emacs, -e produce logging information without adornments"
  735. + lSep);
  736. msg.append(" -lib <path> specifies a path to search for jars and classes"
  737. + lSep);
  738. msg.append(" -logfile <file> use given file for log" + lSep);
  739. msg.append(" -l <file> ''" + lSep);
  740. msg.append(" -logger <classname> the class which is to perform logging" + lSep);
  741. msg.append(" -listener <classname> add an instance of class as a project listener"
  742. + lSep);
  743. msg.append(" -noinput do not allow interactive input" + lSep);
  744. msg.append(" -buildfile <file> use given buildfile" + lSep);
  745. msg.append(" -file <file> ''" + lSep);
  746. msg.append(" -f <file> ''" + lSep);
  747. msg.append(" -D<property>=<value> use value for given property" + lSep);
  748. msg.append(" -keep-going, -k execute all targets that do not depend" + lSep);
  749. msg.append(" on failed target(s)" + lSep);
  750. msg.append(" -propertyfile <name> load all properties from file with -D" + lSep);
  751. msg.append(" properties taking precedence" + lSep);
  752. msg.append(" -inputhandler <class> the class which will handle input requests" + lSep);
  753. msg.append(" -find <file> (s)earch for buildfile towards the root of" + lSep);
  754. msg.append(" -s <file> the filesystem and use it" + lSep);
  755. msg.append(" -nice number A niceness value for the main thread:" + lSep
  756. + " 1 (lowest) to 10 (highest); 5 is the default"
  757. + lSep);
  758. msg.append(" -nouserlib Run ant without using the jar files from" + lSep
  759. + " ${user.home}/.ant/lib" + lSep);
  760. msg.append(" -noclasspath Run ant without using CLASSPATH" + lSep);
  761. msg.append(" -noproxy Java 1.5 only: do not use the OS proxies" +
  762. lSep);
  763. msg.append(" -main <class> override Ant's normal entry point");
  764. System.out.println(msg.toString());
  765. }
  766. /**
  767. * Prints the Ant version information to <code>System.out</code>.
  768. *
  769. * @exception BuildException if the version information is unavailable
  770. */
  771. private static void printVersion() throws BuildException {
  772. System.out.println(getAntVersion());
  773. }
  774. /**
  775. * Cache of the Ant version information when it has been loaded.
  776. */
  777. private static String antVersion = null;
  778. /**
  779. * Returns the Ant version information, if available. Once the information
  780. * has been loaded once, it's cached and returned from the cache on future
  781. * calls.
  782. *
  783. * @return the Ant version information as a String
  784. * (always non-<code>null</code>)
  785. *
  786. * @exception BuildException if the version information is unavailable
  787. */
  788. public static synchronized String getAntVersion() throws BuildException {
  789. if (antVersion == null) {
  790. try {
  791. Properties props = new Properties();
  792. InputStream in =
  793. Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
  794. props.load(in);
  795. in.close();
  796. StringBuffer msg = new StringBuffer();
  797. msg.append("Apache Ant version ");
  798. msg.append(props.getProperty("VERSION"));
  799. msg.append(" compiled on ");
  800. msg.append(props.getProperty("DATE"));
  801. antVersion = msg.toString();
  802. } catch (IOException ioe) {
  803. throw new BuildException("Could not load the version information:"
  804. + ioe.getMessage());
  805. } catch (NullPointerException npe) {
  806. throw new BuildException("Could not load the version information.");
  807. }
  808. }
  809. return antVersion;
  810. }
  811. /**
  812. * Prints the description of a project (if there is one) to
  813. * <code>System.out</code>.
  814. *
  815. * @param project The project to display a description of.
  816. * Must not be <code>null</code>.
  817. */
  818. private static void printDescription(Project project) {
  819. if (project.getDescription() != null) {
  820. project.log(project.getDescription());
  821. }
  822. }
  823. /**
  824. * Prints a list of all targets in the specified project to
  825. * <code>System.out</code>, optionally including subtargets.
  826. *
  827. * @param project The project to display a description of.
  828. * Must not be <code>null</code>.
  829. * @param printSubTargets Whether or not subtarget names should also be
  830. * printed.
  831. */
  832. private static void printTargets(Project project, boolean printSubTargets) {
  833. // find the target with the longest name
  834. int maxLength = 0;
  835. Enumeration ptargets = project.getTargets().elements();
  836. String targetName;
  837. String targetDescription;
  838. Target currentTarget;
  839. // split the targets in top-level and sub-targets depending
  840. // on the presence of a description
  841. Vector topNames = new Vector();
  842. Vector topDescriptions = new Vector();
  843. Vector subNames = new Vector();
  844. while (ptargets.hasMoreElements()) {
  845. currentTarget = (Target) ptargets.nextElement();
  846. targetName = currentTarget.getName();
  847. if (targetName.equals("")) {
  848. continue;
  849. }
  850. targetDescription = currentTarget.getDescription();
  851. // maintain a sorted list of targets
  852. if (targetDescription == null) {
  853. int pos = findTargetPosition(subNames, targetName);
  854. subNames.insertElementAt(targetName, pos);
  855. } else {
  856. int pos = findTargetPosition(topNames, targetName);
  857. topNames.insertElementAt(targetName, pos);
  858. topDescriptions.insertElementAt(targetDescription, pos);
  859. if (targetName.length() > maxLength) {
  860. maxLength = targetName.length();
  861. }
  862. }
  863. }
  864. printTargets(project, topNames, topDescriptions, "Main targets:",
  865. maxLength);
  866. //if there were no main targets, we list all subtargets
  867. //as it means nothing has a description
  868. if (topNames.size() == 0) {
  869. printSubTargets = true;
  870. }
  871. if (printSubTargets) {
  872. printTargets(project, subNames, null, "Other targets:", 0);
  873. }
  874. String defaultTarget = project.getDefaultTarget();
  875. if (defaultTarget != null && !"".equals(defaultTarget)) {
  876. // shouldn't need to check but...
  877. project.log("Default target: " + defaultTarget);
  878. }
  879. }
  880. /**
  881. * Searches for the correct place to insert a name into a list so as
  882. * to keep the list sorted alphabetically.
  883. *
  884. * @param names The current list of names. Must not be <code>null</code>.
  885. * @param name The name to find a place for.
  886. * Must not be <code>null</code>.
  887. *
  888. * @return the correct place in the list for the given name
  889. */
  890. private static int findTargetPosition(Vector names, String name) {
  891. int res = names.size();
  892. for (int i = 0; i < names.size() && res == names.size(); i++) {
  893. if (name.compareTo((String) names.elementAt(i)) < 0) {
  894. res = i;
  895. }
  896. }
  897. return res;
  898. }
  899. /**
  900. * Writes a formatted list of target names to <code>System.out</code>
  901. * with an optional description.
  902. *
  903. *
  904. * @param project the project instance.
  905. * @param names The names to be printed.
  906. * Must not be <code>null</code>.
  907. * @param descriptions The associated target descriptions.
  908. * May be <code>null</code>, in which case
  909. * no descriptions are displayed.
  910. * If non-<code>null</code>, this should have
  911. * as many elements as <code>names</code>.
  912. * @param heading The heading to display.
  913. * Should not be <code>null</code>.
  914. * @param maxlen The maximum length of the names of the targets.
  915. * If descriptions are given, they are padded to this
  916. * position so they line up (so long as the names really
  917. * <i>are</i> shorter than this).
  918. */
  919. private static void printTargets(Project project, Vector names,
  920. Vector descriptions, String heading,
  921. int maxlen) {
  922. // now, start printing the targets and their descriptions
  923. String lSep = System.getProperty("line.separator");
  924. // got a bit annoyed that I couldn't find a pad function
  925. String spaces = " ";
  926. while (spaces.length() <= maxlen) {
  927. spaces += spaces;
  928. }
  929. StringBuffer msg = new StringBuffer();
  930. msg.append(heading + lSep + lSep);
  931. for (int i = 0; i < names.size(); i++) {
  932. msg.append(" ");
  933. msg.append(names.elementAt(i));
  934. if (descriptions != null) {
  935. msg.append(
  936. spaces.substring(0, maxlen - ((String) names.elementAt(i)).length() + 2));
  937. msg.append(descriptions.elementAt(i));
  938. }
  939. msg.append(lSep);
  940. }
  941. project.log(msg.toString(), Project.MSG_WARN);
  942. }
  943. }