Wrapping a tool with AbstractToolExtension and AbstractExecWrapperWithExtensionTask

Step 1 - Create an execution specification

Firstly create an execution specification as described in the previous section

Step 2 - Create an extension

We start with an extension class that will only be used as a project extension.

MyToolExtension.groovy
@CompileStatic
class MyToolExtension extends AbstractToolExtension<MyToolExtension> { (1)
    static final String NAME = 'toolConfig'

    MyToolExtension(ProjectOperations po) { (2)
        super(po)
    }

    MyToolExtension(Task task, ProjectOperations po, MyToolExtension projectExt) {
        super(task, po, projectExt) (3)
    }

    @Override
    protected String runExecutableAndReturnVersion() throws ConfigurationException { (4)
        try {
            projectOperations.execTools.parseVersionFromOutput( (5)
                ['--version'], (6)
                executablePathOrNull(), (7)
                { String output -> '1.0.0' } (8)
            )
        } catch (RuntimeException e) {
            throw new ConfigurationException('Cannot determine version', e)
        }
    }

    @Override
    protected ExecutableDownloader getDownloader() { (9)
    }
}
1 Derive from AbstractToolExtension. This will provide methods for setting the executable.
2 Create a constructor for attaching the extension to a project.
3 You will also need a constructor for attaching to a task. In this case you will also need to specify the name of the project extension. By convention, always have the task and project extension as the same name. For simplicity, we’ll ignore this constructor and return to it a bit later.
4 When a user specified a tool by path or search path, we ned a different way of obtaining the version. Implement this method to perform that task.
5 Using parseVersionFromOutput is the easiest way to implement this.
6 Pass the appropriate parameters that will return output that declares the version.
7 executablePathOrNull is the easiest way to obtain the path to the executable that was set earlier.
8 Provide a parser to extract the version from output. The parser is supplied the output from running the executable with the given command-line parameters.
9 Returns an instance that will return the locaiton of an executable buy possibly downloading it if not available locally. See for more details on implementing your own.

Step 3 - Create the task class

MyExtensionWrapperTask.groovy
@CompileStatic
class MyExtensionWrapperTask extends AbstractExecWrapperWithExtensionTask<MyToolExtension, MyCmdExecSpec> { (1)

    MyExtensionWrapperTask() {
        super()
        this.execSpec = new MyCmdExecSpec(this) (2)
        this.executableLocation = toolExtension.executable (3)
    }

    @Override
    protected MyCmdExecSpec getExecSpec() { (4)
        this.execSpec
    }

    @Override
    protected MyToolExtension getToolExtension() { (5)
        project.extensions.getByType(MyToolExtension)
    }

    @Override
    protected Provider<File> getExecutableLocation() { (6)
       this.executableLocation
    }

    private final Provider<File> executableLocation
    private final MyCmdExecSpec execSpec
}
1 Your task class must extend AbstractExecWrapperWithExtensionTask and specify the type of the associated execution specification as well as the type of the extension.
2 Cache the lazy-evaluated location of the executable.
3 Create a execution specification that is associated with the task.
4 In most cases the implements of getExecSpec is to return an instance that was created in the constructor.
5 Return the location of the extension. This is just a shortcut method and cannot be called from a task action.
6 A method to return the location of an executable. In most cases this will simply be the value of a private field.

Step 4 - Apply this via plugin

Create both extension and the task in the plugin.