Is there a functional programming pattern for Gradle Tasks?


#1

I’m interested in mapping a gradle Jar task over a set of Jars. Basically I want to process a given set of jars and filter common files out of each Jar.

I currently have the set of Jars in a tmp build direcotry, so how would I create a Jar task that can be applied to a set of Jars? By default a Jar task only outputs a single Jar.

One way to do this would be to create a custom task applies a closure to each individual Jar, but its not clear how a new “anonymous” Jar task could be placed inside of this closure?


(Peter Niederwieser) #2

I’m not quite sure what you are asking for. A ‘Jar’ task always produces a single Jar file, and it never operates on a given Jar.


#3

The second post in this thread has some insight. The idea is to programmatically create the tasks during configuration. Is this the preferred technique?

If so, how do you access the dependencies artifacts of a configuration during the configuration step? Some of the jars I need to process are coming from an external maven repo.


(Peter Niederwieser) #4

The second post in this thread has some insight. The idea is to programmatically create the tasks during configuration. Is this the preferred technique?

Preferred technique for what? It’s certainly a common technique.

If so, how do you access the dependencies artifacts of a configuration during the configuration step? Some of the jars I need to process are coming from an external maven repo.

Still not sure what you are trying to do, but in the simplest case, you just iterate over the configuration.


#5

Peter, your post here shows how a jar task can operate on a jar.

In my case I need to do this over many jars.

Some of the jars I need to access are part of the project dependencies. Can you show me how to setup a configuration that would configure the Jar tasks that can take the dependency jars as input?


#6

I had an issue resolving the locations of the dependency jars. The following code should have worked:

configurations.compile.collect()

It wasn’t working for me because I was using the artifactory plugin to setup the maven resolver. There must be a bug because it would not let the line above to execute. Using the native repo configuration commands fixed the issue.


(james.childers) #7

The broader issue raised here seems to me one of reducing code duplication. I’ve run into this several times since switching over to Gradle, and have struggled each time. The broad pattern is:

  1. Have several similar tasks. For example, we currently have tasks which are responsible for creating and destroying local databases for development use. These tasks look similar to this:
task createLocalDb(type: Exec) {
    doFirst {
        mkdir 'database/tablespace'
    }
          // ... snip ....
    commandLine 'sqlplus',
            'SYSTEM '+ '/' + project.dbPassword,
            '@' + 'create_env.sql'
}
  task destroyLocalDb(type: Exec) {
    // ... snip ....
    commandLine 'sqlplus'
  commandLine 'sqlplus',
            'SYSTEM '+ '/' + project.dbPassword,
            '@' + 'destroy_env.sql'
       doLast {
        delete 'oracle/tablespace'
    }
}

Now, the only difference between these two tasks is the script they execute, and the presence of doFirst/doLast blocks. I’ve scoured through the documentation but haven’t found a good way to reduce the duplication here. I’ve tried creating closures, but as soon as they are called they lose the context which they’re being executed in, which means you don’t have access to the project, or any of the configuration for the task. I also looked for a way to pass the task to a closure, e.g.:

task createLocalDb(type Exec) {
    sqlExecClosure(this, 'create_env.sql')
}

Where ‘this’ is a reference to the current task, but did not find a way to do so.

Basically, I think what is being asked for is an example of a pattern wherein boilerplate code for tasks can be reduced, without losing access to the task’s context.


#8

The pattern I referenced at the top was the key.

I basically wrote a function that dynamically created tasks. There is no way to create an unnamed task as far as i can tell. That is what I was looking for. The work around is to just dynamically generate new task names for each task you create. Its a little clunky because the dynamic names are referenced as inputs to other tasks. If you don’t know how these tasks are created in the project then it might be confusing

I call the function multiple times in my project. I could have put my input args into a nest list, and then iterated over the list to call the function, but that would have been overkill in this case.

For the question above I think this post might have some insight to improve your code-reuse of an exec task.