How to reconfigure task in plugin?


(Maxim G) #1

I have a task:

class Downloader2 extends DefaultTask {
    @Input
    String src
      @OutputFile
    File dest
      @TaskAction
    void download() {
        logging.setLevel(LogLevel.INFO)
        ant.get(src: src, dest: dest, verbose: true)
    }
}

that lives in plugin:

class KernelExtension {
    String urlSrc = "http://www.kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.35/linux-2.6.35.13.tar.bz2"
    String downloadDest = "download/linux-2.6.35.13.tar.bz2"
}
  class KernelPlugin implements Plugin<Project>{
      def void apply(Project project){
        project.apply(plugin: DcslnxUtilsPlugin)
        project.extensions.create("kernelConfig", KernelExtension)
          project.task("download", type: Downloader2) {
            src = project.kernelConfig.urlSrc
            dest = new File(project.kernelConfig.downloadDest)
        }
   }
}

In build.gradle i’m trying to reconfigure urlSrc:

apply plugin: 'kernel'
project.kernelConfig{
    urlSrc = "some url"
}

seems gradle (version 1.1) uses old value :frowning: How should i reconfigure task in plugin?


(René Groeschke) #2

Hey Maxim, the code in the apply method of KernelPlugin is executed directly when apply plugin: ‘kernel’ is called. This means that the assignment of src=project.kernelConfig.urlSrc has already happened. You can either use conventionmapping to defere the assignment (as an example you can have a look at Gradles ApplicationPlugin). Another more simpler option for your use case might be to reconfigure the src property of your Downloader2 task directly:

apply plugin: 'kernel'
download{
    src = "some url"
}

Hope that helps,

cheers,

René


(Maxim G) #3

Thanks René, I have tried conventionMapping

def convention = new KernelConvention(project)
        project.convention.plugins.kernel = convention
          def download = project.tasks.add('download', Downloader2)
        download.conventionMapping.src = {convention.urlSrc}
        download.conventionMapping.dest = {file(convention.downloadDest)}
          def unpack = project.tasks.add('unpack', Untar)
        unpack.conventionMapping.src = {file(convention.downloadDest)}
        unpack.conventionMapping.dest = {file(convention.unpackDest)}
        unpack.dependsOn(download)

still for chained tasks have got an exception:

* What went wrong:
Could not determine the dependencies of task ':unpack'

Your simpler option works in the case of isolated task. But how about chained tasks?


(Peter Niederwieser) #4

Convention mapping works just as well for interdependent tasks. A stack trace including causes might help to explain where the problem is.

By the way, extension objects have effectively replaced convention objects, so you should keep using the former. They support convention mapping as well.


(Maxim G) #5

Thanks for the point Peter, explicit project.file() fixed the problem with the exception. Anyway to support conventin mapping I should extend ConventionTask, shouldn’t I?


(Peter Niederwieser) #6

You don’t have to, but it’s a decent choice if you are using Java rather than Groovy to implement the task class.

In case it hasn’t been mentioned in this topic, convention mapping is still considered an internal feature. Then again, it’s often the best solution to the lazy initialization problem.


(Maxim G) #7

Still I’m confused :frowning: Complete source in build.gradle:

import org.gradle.api.internal.ConventionTask
  class Downloader2 extends ConventionTask {
    @Input
    String src
      @OutputFile
    File dest
      @TaskAction
    void download() {
        println "action download"
        dest?.parentFile?.mkdirs()
        logging.setLevel(LogLevel.INFO)
        println src
        println dest
        ant.get(src: src, dest: dest, verbose: true)
    }
}
  class KernelExtension {
    String urlSrc = "http://www.kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.35/linux-2.6.35.13.tar.bz2"
    String downloadDest
      File getDownloadDest() {
        downloadDest = new File("download/${urlSrc.split('/')[-1]}")
    }
}
  class KernelPlugin implements Plugin<Project> {
    def void apply(Project project) {
        project.extensions.create("kernel", KernelExtension)
          def download = project.tasks.add('download', Downloader2)
        download.conventionMapping.src = {project.kernel.urlSrc}
        download.conventionMapping.dest = {project.kernel.downloadDest}
    }
}
    apply plugin: KernelPlugin
  kernel.urlSrc = "http://www.sai.msu.su/apache//apr/apr-1.4.6.tar.gz"
  download {
    println "reconfigure"
//
  src = "http://www.sai.msu.su/apache//apr/apr-1.4.6.tar.gz"
//
  dest = new File("download/${src.split('/')[-1]}").getCanonicalFile()
}
  defaultTasks 'download'

Output:

reconfigure
:download
action download
null
null
  FAILURE: Build failed with an exception.
  * Where:
Build file '/home/max/repo/dcslnx2_utils/buildTest2.gradle' line: 17
  * What went wrong:
Execution failed for task ':download'.
> java.net.MalformedURLException: no protocol: null
...

(Peter Niederwieser) #8

A property for which convention mapping is used has to be called with its getter if accessed from within the same class. Otherwise Groovy will access the field directly, and there is no chance for the convention mapping to kick in. In other words, try ‘println getSrc()’ and ‘println getDest()’.


(Maxim G) #9

Thanks Peter, you made my day :slight_smile: