12

I have an ant buildfile that is often run from vastly different environments. By default, I'm looking for the same behavior as using:

ant -q

However, since some team member's configurations vary, specifying the -q option in each person's environment is not easily accomplished in a uniform way (some people run ant from eclipse, some from the command line, some from debugging/profiling tools, etc. Each with a different method for specifying ant arguments like -q)

So I'm seeking a way for the ant file to call itself quietly...

Something like the following would be ideal:

<target name="default">
    <antcall quiet="yes" target="build" /> <!-- doesn't work -->
</target>

Can anyone think of anyway to accomplish something like this? All I'm after is for the build to run quietly whenever the default target is ran, regardless of whether -q is set.

tshepang
  • 12,111
  • 21
  • 91
  • 136
gMale
  • 17,147
  • 17
  • 91
  • 116

4 Answers4

21

One option might be to set the logging level from within the target.

You can access loggers by means of a short script task. Something like:

<target ... >
    <script language="javascript">
        var logger = project.getBuildListeners( ).firstElement( );
        logger.setMessageOutputLevel( 0 );
    </script>
    ...
</target>

I'm not familiar with how Eclipse calls Ant, but it might be necessary to iterate over all the build listeners to get 'silence' all round.

Suggest that how ever you end up doing this, you make it easy to switch back to verbose running.

Edit - response to comment: You can access project properties from within the script using project.getProperty():

<property name="verboseFlag" value="1" />
<script language="javascript">
    var logger = project.getBuildListeners().firstElement();
    var verboseMode = project.getProperty( "verboseFlag" )
    if ( ! "1".equals( verboseMode ) )
        logger.setMessageOutputLevel( 0 );
</script>

(Somewhat old) API docs are here, including for the project class.

martin clayton
  • 76,436
  • 32
  • 213
  • 198
  • @martin: wow. I didn't even know javascript could be used with Ant. That's amazing. This worked perfectly, when I used *setMessageOutputLevel(1)*, only my echo commands printed. That's exactly what I'm after. Now, all I have to do is test whether this works in the other environments from which we run Ant (command line, eclipse, etc.)... – gMale Mar 29 '11 at 13:59
  • @martin: on 'line 2' of the script is there a way to say something like, `if(verboseFlagNotSet) logger.setMessageOutputLevel(1);` That is, do you know of a way to check the status of the verbose flag? – gMale Mar 29 '11 at 14:03
  • @gmale - should be able to. I added an example to the answer. You can read (and set) Ant properties from within the JS. – martin clayton Mar 29 '11 at 16:14
  • @martin: Thanks for your answer, it is useful as well but... sorry, I should have been more clear. By "verbose flag" I meant the -v option. Meaning, is there a way to detect when the user has called ant with the verbose flag set as in: `ant -v -f build.xml`. So when the user specifies the verbose flag, I want to leave the logger alone. – gMale Mar 30 '11 at 13:42
  • The logging level is directly passed to ants logging framework, i think you can't access it after ant has started. But you may check with ... like i used in the groovy example. One lowlevel approach would be blablabla and afterwards check the filelength. Also see http://ant.apache.org/manual/Tasks/echo.html, there's a detailled table that explains what gets logged when ant gets started with -v, -d, -q loglevel or default. – Rebse Mar 30 '11 at 18:52
  • The Ant BuildLogger interface doesn't include a method to get the log level. If you have a DefaultLogger instance you could introspect into it and get the (protected) msgOutputLevel field value, but I couldn't recommend that, and it's no good for other loggers. – martin clayton Mar 30 '11 at 21:46
7

Based on other answers:

<macrodef name="quiet">
    <element name="body" implicit="yes"/>
    <sequential>
        <script language="javascript">
            project.getBuildListeners().firstElement().setMessageOutputLevel(0);
        </script>
        <body/>
        <script language="javascript">
            // TODO: restore last log level
            project.getBuildListeners().firstElement().setMessageOutputLevel(2);
        </script>
    </sequential>
</macrodef>

<target name="test-quiet">
    <quiet>
        <echoproperties/>
    </quiet>
</target>
Vadzim
  • 24,954
  • 11
  • 143
  • 151
5

For controlling the loglevel from within your ant script you could take this simple task =

public class SetLogLevel extends Task
{
    private int logLevel = -1;

    public void execute()
    {
        if (logLevel == -1)
        {
            throw new BuildException("Error - No Loglevel specified !!");
        }
        Vector listeners = this.getProject().getBuildListeners();
        for (Iterator i = listeners.iterator(); i.hasNext();)
        {
            BuildListener listener = (BuildListener) i.next();
            if (listener instanceof BuildLogger)
            {
                BuildLogger logger = (BuildLogger) listener;
                logger.setMessageOutputLevel(logLevel);
            }
        }
    }

    /**
     * 
     *  @see org.apache.tools.ant.taskdefs.Echo$EchoLevel
     * 
     */

    public void setLevel(EchoLevel echoLevel) {
        String option = echoLevel.getValue();
        if (option.equals("error")) {
            logLevel = Project.MSG_ERR;
        } else if (option.equals("warning")) {
            logLevel = Project.MSG_WARN;
        } else if (option.equals("info")) {
            logLevel = Project.MSG_INFO;
        } else if (option.equals("verbose")) {
            logLevel = Project.MSG_VERBOSE;
        } else {
            // must be "debug"
            logLevel = Project.MSG_DEBUG;
        }
    }
}

map it to a taskdef and use it like that =

<setloglevel level="error"/>

... only errors should be listed

<setloglevel level="info" />

... loglevel info again

That's what i do to shorten logfiles when using talkative tasks like f.e. cvs task

Rebse
  • 10,307
  • 2
  • 38
  • 66
  • I'm not familiar with doing this kind of thing (extending ant via java) but I'll Google the details of how to get this to work and then give it a try... – gMale Mar 28 '11 at 19:29
  • Basically it's all about extending the org.apache.tools.ant.Task – Rebse Mar 28 '11 at 20:11
  • 1
    Basically it's all about extending the org.apache.tools.ant.Task Normally you have more than one selfwritten task and put them into a jar. Into this jar there is a xmlfile called antlib.xml that does the mapping between the taskname and the classname. Put that jar in sight for ant - but not simply in %ANT_HOME%/lib because you're polluting your ant installation. Better to put in some ../extralibs folder and start ant with -lib path/to/extralibs option. Then in your antscript you load your task(s) like that : – Rebse Mar 28 '11 at 20:18
  • thanks. That's all very helpful. Funny, my first instinct would be to put that Jar in my ant lib directory, since it would have reusable ant stuff. For now, the only thing in my ant lib is ivy. I guess it would be handy to put this jar in the local ivy repository, then I could retrieve it automatically the same way I do ant-contrib... – gMale Mar 29 '11 at 14:07
4

After reading Martin's answer, i think it's most comfortable to put the whole stuff in a scriptdef. Here's a solution with groovy =

<project>

  <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>

  <!-- testproperty referenced from verboseflag attribute 
       comment out to make it unset -->
  <property name="someverboseflag" value="whatever"/>

    <scriptdef name="setloglevel" language="groovy">
      <attribute name="loglevel"/>
      <attribute name="verboseflag"/>

     switch (attributes.'loglevel') {
        case 'error':
          project.getBuildListeners()[0].setMessageOutputLevel(0)
          break
        case 'warn':
          project.getBuildListeners()[0].setMessageOutputLevel(1)
          break
        case 'info':
          project.getBuildListeners()[0].setMessageOutputLevel(2)
          break
        case 'verbose':
          project.getBuildListeners()[0].setMessageOutputLevel(3)
          break
        case 'debug':
          project.getBuildListeners()[0].setMessageOutputLevel(4)
          break
     }

        if (project.getProperty(attributes.'verboseflag') == null)
        {
          println "Property " + attributes.'verboseflag' + " not set, default => Loglevel WARN !"   
          project.getBuildListeners()[0].setMessageOutputLevel(1)
        }
  </scriptdef>

    <!-- the loglevel given in attribute loglevel is only used
         when verboseflag attribute is set, otherwise
         loglevel WARN is used -->
    <setloglevel loglevel="debug" verboseflag="someverboseflag"/>

    <!-- test -->
    <echo level="error">getting logged when Loglevel ERROR and higher..</echo>
    <echo level="warning">getting logged when Loglevel WARN and higher..</echo>
    <echo level="info">getting logged when Loglevel INFO and higher..</echo>
    <echo level="verbose">getting logged when Loglevel VERBOSE and higher..</echo>
    <echo level="debug">getting logged when Loglevel DEBUG..</echo>

</project>

Every scripting language running with Bean Scipting Framework in Java VM may be used for scripting in ant with full access to the ant api - it's a matter of taste. Used Javascript, Beanshell, (J)ruby before and lately switched to Groovy.

Rebse
  • 10,307
  • 2
  • 38
  • 66
  • 3
    + 1 for blowing my mind! lol. You can use groovy in an ant script!!! that almost makes me drool. – gMale Mar 30 '11 at 13:45
  • :-) Groovy even provides it's own task .... Beside groovy there's a bunch of other languages running via Bean Scripting Framework in Ant : (J)ruby, Beanshell, Javascript (Rhino from Mozilla), Jython, Judoscript .. One language for every taste / fetish – Rebse Mar 30 '11 at 18:13
  • 3
    btw. there's also the other way around, using Ant from Groovy, without xml, see = http://groovy.codehaus.org/Using+Ant+from+Groovy – Rebse Mar 30 '11 at 18:43