Cannot impose a one time ordering on tasks


(gus.heck) #1

First off, I am already aware of GRADLE-427. I am also aware of mustRunAfter and dependsOn. I have found .execute() to be unreliable.

In all my code, including builds, I strive for reuse of code. mustRunAfter and dependsOn permanently attach relationships to other tasks to the present task. This interferes with the reuse of tasks. This is fairly obvious with dependsOn because it forces other tasks to run, and subtler with mustRunAfter where adding a new dependency can disrupt a previously well sorted order in an unclear fashion, and precludes a reverse ordering at any time in the future.

Consider this:

task stopTomcat << {
    println 'Stopping tomcat...'
    def proc = project.ext.stopT.execute()
    proc.waitFor()
    sleep 3000
}
  task startTomcat << {
    println 'Starting tomcat...'
    def proc = project.ext.startT.execute()
    proc.waitFor()
}

I may well want to start tomcat, do something (UI tests?) and then stop tomcat. I may also want to stop tomcat, do something (drop a jar in /lb?) and then start it again. I may also want to start tomcat and have gradle finish, test my code manually, then run a task to stop tomcat.

In all cases order is important, and must be as specified, and it’s not acceptable for either task to require the other to be run first. This situation leaves me red in the face with bulging veins screaming at the screen “I know the order! Let me tell you the #$#@% order”

Ok maybe not :slight_smile: but it has wasted a bunch of my time, and is beginning to make me look silly for having promoted gradle in our project… The ability to execute segments of code in a particular order is something one assumes is there and it’s quite a shock to find out that it’s not possible! If people ask me about this I can only say… “uh it’s a suprise to me too”

Functions are not the solution because I want to do these sorts of things with extensions of the Copy task too, and you can’t convert a task to a function, and execute() in a function is unreliable.

Personally I would find it most convenient if you just did what GRADLE-427 asked for, but any syntax that works is fine with me, even making execute reliable.


(Attila Kelemen) #2

What I did when having a similar issue is that I created a factory method for the task. So in the Tomcat example, I would have a method:

void createStartTomcatTask(Project project, String taskName) {
    project.task taskName, {
        doLast {
            println 'Starting tomcat...'
            def proc = project.ext.startT.execute()
            proc.waitFor()
        }
    }
}

And call it like ‘createStartTomcatTask(project, ‘startTomcatForMyPurpose’)’. This way you can have any number of this task.

Apart from that “fixing” GRADLE-427 as originally reqested would be a broken design, I don’t think that the “dependency order” would solve your problem because it still wouldn’t allow you to call a task multiple times.


(gus.heck) #3

That’s an interesting idea, but I’m not quite sure how it would apply to something like

task untarServer(type:Copy) {
    from tarTree('build/libs/server.tar.gz')
    into project.ext.tomcat + '../'
}

(Attila Kelemen) #4

Depends on why you would like to execute this task multiple times and why a simple ‘dependsOn’ is not enough. But in general, the above template can be applied (although I don’t see why it is benefical):

void createUntarServerTask(Project project, String taskName) {
    project.task [type: Copy], taskName, {
        doLast {
            from tarTree('build/libs/server.tar.gz')
            into project.ext.tomcat + '../'
        }
    }
}

To be honest, the server start example isn’t the best for this purpose because probably they would start the same server and there is no ordering relation defined between start and stop tasks. That is, you can’t (as far as I know) tell Gradle that nothing should be done between two tasks.

To start and stop a server before and after a particular task, I would use ‘doFirst’ combined with the new ‘finalizedBy’ feature.


(Andrew Oberstar) #5

If it’s really “one-time” ordering, doesn’t the command line work just fine for this? As long as there aren’t other dependencies in place already, the order on the command line is respected.

Alternatively, if it’s more that you have different use cases that require different orderings, try taking a look at the ‘buildTypes’ functionality that they use in the core Gradle build.

The helper code is here with the usage in their build.gradle.