/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Ant", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
*
Takes the "find" property as a suffix to append to each * parent directory in seach of a build file. Once the * root of the file-system has been reached an exception * is thrown. */ public File getBuildFile() throws BuildException { // if buildFile was not specified on the command line, if (buildFile == null) { // but -find then search for it if (searchForThis != null) { buildFile = findBuildFile(System.getProperty("user.dir"), searchForThis); } else { buildFile = new File(DEFAULT_BUILD_FILENAME); } } getProject().setUserProperty("ant.file" , buildFile.getAbsolutePath() ); return buildFile; } /** Return an (initialized) project constructed using the current * settings. * This will not load the build.xml file - you can 'load' the * project object with tasks manually or execute 'standalone' * tasks in the context of the project. */ public Project getProject() { if( newProject!=null ) return newProject; loadProperties(); helper=ProjectHelper.getProjectHelper(); newProject = helper.createProject(coreLoader); newProject.setCoreLoader(coreLoader); addBuildListeners(newProject); newProject.fireBuildStarted(); newProject.init(); newProject.setUserProperty("ant.version", getAntVersion()); // set user-define properties Enumeration e = definedProps.keys(); while (e.hasMoreElements()) { String arg = (String)e.nextElement(); String value = (String)definedProps.get(arg); newProject.setUserProperty(arg, value); } return newProject; } private static String antVersion = null; /** @experimental * Ant version should be combined with the ProjectHelper version and type, * since it'll determine the set of features supported by ant ( at the xml * level ). */ public static synchronized String getAntVersion() throws BuildException { if (antVersion == null) { try { Properties props = new Properties(); InputStream in = Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt"); props.load(in); in.close(); String lSep = System.getProperty("line.separator"); StringBuffer msg = new StringBuffer(); msg.append("Apache Ant version "); msg.append(props.getProperty("VERSION")); msg.append(" compiled on "); msg.append(props.getProperty("DATE")); antVersion = msg.toString(); } catch (IOException ioe) { throw new BuildException("Could not load the version information:" + ioe.getMessage()); } catch (NullPointerException npe) { throw new BuildException("Could not load the version information."); } } return antVersion; } // -------------------- Bean methods -------------------- Throwable error = null; /** Clean up allocated resources and finish the processing of the * current Project. */ public void done() { newProject.fireBuildFinished(error); } /** * Process an XML file and execute the targets. * * This method can be called multiple times, eventually after setting different * build file and different targets - all executions will happen in the * same execution context ( project ). */ public void processBuildXml() throws BuildException { checkBuildFile(); File buildFile=getBuildFile(); Project newProject=getProject(); // first use the ProjectHelper to create the project object // from the given build file. String noParserMessage = "No JAXP compliant XML parser found. Please visit http://xml.apache.org for a suitable parser"; try { Class.forName("javax.xml.parsers.SAXParserFactory"); helper.parse(newProject, buildFile); } catch (NoClassDefFoundError ncdfe) { throw new BuildException(noParserMessage, ncdfe); } catch (ClassNotFoundException cnfe) { throw new BuildException(noParserMessage, cnfe); } catch (NullPointerException npe) { throw new BuildException(noParserMessage, npe); } // make sure that we have a target to execute if (targets.size() == 0) { targets.addElement(newProject.getDefaultTarget()); } newProject.executeTargets(targets); } public void execute() throws BuildException { try { if( redirectOutput ) { pushSystemOut(); } processBuildXml(); } catch(RuntimeException exc) { error = exc; throw exc; } catch(Error err) { error = err; throw err; } finally { done(); if( redirectOutput ) popSystemOut(); } } // -------------------- Private methods -------------------- private void checkBuildFile() throws BuildException { File buildFile=getBuildFile(); // make sure buildfile exists if (!buildFile.exists()) { System.out.println("Buildfile: " + buildFile + " does not exist!"); throw new BuildException("Build failed"); } // make sure it's not a directory (this falls into the ultra // paranoid lets check everything catagory if (buildFile.isDirectory()) { System.out.println("What? Buildfile: " + buildFile + " is a dir!"); throw new BuildException("Build failed"); } // track when we started if (msgOutputLevel >= Project.MSG_INFO) { System.out.println("Buildfile: " + buildFile); } } private PrintStream oldErr=null; private PrintStream oldOut=null; private SecurityManager oldsm = null; private void pushSystemOut() { oldErr = System.err; oldOut = System.out; // use a system manager that prevents from System.exit() // only in JDK > 1.1 if ( !Project.JAVA_1_0.equals(Project.getJavaVersion()) && !Project.JAVA_1_1.equals(Project.getJavaVersion()) ){ oldsm = System.getSecurityManager(); //SecurityManager can not be installed here for backwards //compatability reasons (PD). Needs to be loaded prior to //ant class if we are going to implement it. //System.setSecurityManager(new NoExitSecurityManager()); } System.setOut(new PrintStream(new DemuxOutputStream(getProject(), false))); System.setErr(new PrintStream(new DemuxOutputStream(getProject(), true))); } private void popSystemOut() { // put back the original security manager //The following will never eval to true. (PD) if (oldsm != null){ System.setSecurityManager(oldsm); } if( oldOut!=null && oldErr!=null ) { System.setOut(oldOut); System.setErr(oldErr); } } protected void addBuildListeners(Project newProject) { // Add the default listener newProject.addBuildListener(createLogger()); for (int i = 0; i < listeners.size(); i++) { String className = (String) listeners.elementAt(i); try { BuildListener listener = (BuildListener) Class.forName(className).newInstance(); newProject.addBuildListener(listener); } catch(Throwable exc) { throw new BuildException("Unable to instantiate listener " + className, exc); } } } /** * Creates the default build logger for sending build events to the ant log. */ protected BuildLogger createLogger() { BuildLogger logger = null; if (loggerClassname != null) { try { logger = (BuildLogger)(Class.forName(loggerClassname).newInstance()); } catch (ClassCastException e) { System.err.println("The specified logger class " + loggerClassname + " does not implement the BuildLogger interface"); throw new RuntimeException(); } catch (Exception e) { System.err.println("Unable to instantiate specified logger class " + loggerClassname + " : " + e.getClass().getName()); throw new RuntimeException(); } } else { logger = new DefaultLogger(); } logger.setMessageOutputLevel(msgOutputLevel); logger.setOutputPrintStream(out); logger.setErrorPrintStream(err); logger.setEmacsMode(emacsMode); return logger; } /** Load all propertyFiles */ private void loadProperties() { // Load the property files specified by -propertyfile for (int propertyFileIndex=0; propertyFileIndex < propertyFiles.size(); propertyFileIndex++) { String filename = (String) propertyFiles.elementAt(propertyFileIndex); Properties props = new Properties(); FileInputStream fis = null; try { fis = new FileInputStream(filename); props.load(fis); } catch (IOException e) { System.out.println("Could not load property file " + filename + ": " + e.getMessage()); } finally { if (fis != null){ try { fis.close(); } catch (IOException e){ } } } // ensure that -D properties take precedence Enumeration propertyNames = props.propertyNames(); while (propertyNames.hasMoreElements()) { String name = (String) propertyNames.nextElement(); if (definedProps.getProperty(name) == null) { definedProps.put(name, props.getProperty(name)); } } } } // -------------------- XXX Move to FileUtil -------------------- /** * Helper to get the parent file for a given file. * *
Added to simulate File.getParentFile() from JDK 1.2. * * @param file File * @return Parent file or null if none */ private File getParentFile(File file) { String filename = file.getAbsolutePath(); file = new File(filename); filename = file.getParent(); if (filename != null && msgOutputLevel >= Project.MSG_VERBOSE) { System.out.println("Searching in "+filename); } return (filename == null) ? null : new File(filename); } /** * Search parent directories for the build file. * *
Takes the given target as a suffix to append to each * parent directory in seach of a build file. Once the * root of the file-system has been reached an exception * is thrown. * * @param suffix Suffix filename to look for in parents. * @return A handle to the build file * * @exception BuildException Failed to locate a build file */ private File findBuildFile(String start, String suffix) throws BuildException { if (msgOutputLevel >= Project.MSG_INFO) { System.out.println("Searching for " + suffix + " ..."); } File parent = new File(new File(start).getAbsolutePath()); File file = new File(parent, suffix); // check if the target file exists in the current directory while (!file.exists()) { // change to parent directory parent = getParentFile(parent); // if parent is null, then we are at the root of the fs, // complain that we can't find the build file. if (parent == null) { throw new BuildException("Could not locate a build file!"); } // refresh our file handle file = new File(parent, suffix); } return file; } }