Stefan Helmerichs
Stefan Helmerichs

Reputation: 502

Manipulating XML in Gradle/Groovy with new 'file' node

I am trying to manipulate a wildfly 10.1. standalone.xml via gradle buildscript to modify logger settings. I have done this before, and with logger entries, this works as expected. However, now I need to add a new periodic-rotating-file-handler which in itself is not a problem, but it does act up when trying to tell what file to actually log to.

Existing code:

def configFile = {wildflyDir}/standalone/configuration/standalone.xml"
def xml = new XmlSlurper(false,false).parse(configFile)
def logging = xml.profile.subsystem.find{ it['@xmlns'] == "urn:jboss:domain:logging:3.0' }
logging.appendNode {
    logger(category:"loggingCategory") {
        level(name:"LEVEL")
    }
}

This is, as expected, highly functional. Now I need to add a snippet like this:

<periodic-rotating-file-handler>
    <formatter>
        <named-formatter name="PATTERN" />
    </formatter>
    <file path="file.log" relative-to="jboss.logging.dir" />
    <suffix value=".yyyy-MM-dd" />
    <append value="true" />
</periodic-rotating-file-handler>

The problem exists in the file definition, as that one would look like this in the build.gradle file:

file(path:"file.log" "relative-to":"jboss.logging.dir")

And this is being interpreted by gradle as new File(arg1, arg2), so basically it is trying to add a file-Object with the given parameters to the XML.

This is valid, but definitely not what I want, since I just need the corresponding XML Node. I tried escaping in multiple ways:

There have been a few more things I tried, but I cannot recall them due to frustration.

My final attempt was to try and just add an empty file node to the XML, however when using file() gradle did not know which File-constructor to use, and when I used file I got an error: Namespace prefix: file is not bound to a URI

If anyone has any idea how to properly escape file or has another way of adding said file-node to the XML please let me know.

Thank you.

Upvotes: 1

Views: 1767

Answers (1)

daggett
daggett

Reputation: 28634

(1) call builder functions on delegate:

//just declare `file` to emulate problem in usual groovy console 
def file={String a, String b-> println "file: a=$a, b=$b"}

def xml = new XmlSlurper(false,false).parseText('''
    <root>
        <profile>
            <subsystem xmlns="urn:jboss:domain:logging:3.0"/>
        </profile>
    </root>''')

def logging = xml.profile.subsystem.find{ it['@xmlns'] == "urn:jboss:domain:logging:3.0" }

logging.plus{
    logger(category:"loggingCategory") {
        level(name:"LEVEL")
    }
    //be specific that you want to call file function on delegate and not on owner (by default)
    delegate.'file'(path:"file.log", "relative-to":"jboss.logging.dir")
    //or this also works:
    "${'file'}"(path:"file.log", "relative-to":"jboss.logging.dir")

}

println groovy.xml.XmlUtil.serialize(xml)

(2) workaround with XmlParser :

use current as accessor to current parent node

def xml = new XmlParser(false,false).parseText('''
    <root>
        <profile>
            <subsystem xmlns="urn:jboss:domain:logging:3.0"/>
        </profile>
    </root>''')

def logging = xml.profile.subsystem.find{ it['@xmlns'] == "urn:jboss:domain:logging:3.0" }

logging.plus{
    logger(category:"loggingCategory") {
        level(name:"LEVEL")
    }
    current.appendNode("file", [path:"file.log", "relative-to":"jboss.logging.dir"])
}

println groovy.xml.XmlUtil.serialize(xml)

Upvotes: 2

Related Questions