Transmode/gradle-docker

Allow to provide Closure in runCommand()

mbronk opened this issue · 2 comments

Hi,
Currently the runCommand(String cmd) API accepts a String CMD, which (if the Docker-typed task is created 'staticly') mandates that the whole command is available at project evaulation phase.

The idea (feature request) would be to add additional API: runCommand(Closure commandSpec) to allow the actual command to be set at build stage.
Use case being: in some cases the very command is not known till other build tasks run.

Note, there sure exist other/better approaches to solving same issue of deferring command evaluation (using Closure just strikes me as having the lowest cost-to-implement)

That might be useful, to be to defer the evaluation to later. However, I don´t see a example of such case.
Do you have an example of that?

Hey @bjornmagnusson . Thanks for your response! Let me try to illustrate my point (if I failed miserably - please re-ask).
To be honest, my actual use case is very niche (and can be easily overthrown by 'just do it properly' argument :) ) , so let me try something abstract first:

Example1:
Consider a gradle task, called acquireLicense, that (somehow) produces a software activation key and a requirement to install said software inside Docker during your container build. It is one of caese where you wouldn't know the exact CLI to run till the very 'build' phase. (I believe this can rather easily be expanded to all subcases where you need to dynamically get the CLI to run, by either contacting remote servers or depending on other task build results).
The way I think about it, with some creativity, you could say it applies even to the apiPassword param of this plugin as well (that's a little controversial, though)

Example 2:
Another example is a rather simple need for 'consuming' other task's outputs. Assume you have a producePackage task that outputs an RPM package that you need to install inside the container. While you definitely can hard-code the package names in some places, a nice way of installing that inside the container could ideally be expressed as runCommand({ -> "dpkg -i ${producePackage.outputs.files.singleFile}" } (BTW, using a neat closure-based syntax you can copy it inside container already)

Example 3: (not about runCommand but I believe it applies to the general idea)
if you had a container hierarchy (with a base image and a derived image), both build via separate Gradle projects... The only way to tie them together would be a static value of baseImage which implies you need to know the exact name and tag of base before the build even starts. This pushes all the versioning tasks into configuration phase and in some cases (actually - in my case), invokes some I/O as well.

My actual case:
I actually have a set of 'template' tasks that get shared among multiple projects for a very simplistic re-use (via apply from: myCommonTasks.gradle mechanism). Since they aim for reuse, some of the parts (like arguments to the runCommand) are provided via system properties and are 'specialized' by each project that includes them. Thing is, while most of the projects need to run all of the tasks, some only need a couple of them (some tasks get explicitly disabled). Since all the runCommand inputs, for all of the tasks that are added to the task graph need to be instantiated, I end up with providing myProperty = THIS_WILL_NEVER_BE_USED values before the apply from:...
All in all - yes, this is just bad design of my code, nothing more (those tasks should never get created, etc.) and I am definitely going to extract those to a plugin on their own. In other words, if this was the only use case, my proposal doesn't bring any more value than allowing individuals to write more bad code :). That said... I do hope the examples above provide a much more rational explanation, and... fact is most of the built-in plugins and the Gradle's DSL allow you to defer execution of nearly everything, which, aside the usefulness discussion - provides a great deal of flexibility.


tl;dr; I hardly see any case where the inability to defer evaluation of the actual commands couldn't be worked around this way or another. I am rather hoping that the (new) syntax would allow a more convenient way of expressing some intents without resorting to intermediary files or hard-coded names, etc. Not sure how costly would that be to implement, though.