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

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