doLast doesn't prompt user for input but doFirst does?

I have written a task to run my project using a main class chosen via user input however I am a tad confused about prompting the user for input.

My task:

task run(dependsOn: "classes", type: JavaExec) {
    description "Executes the project using the selected main class"
      doFirst {
        def selection = null
        def mainClasses = []
          // Select the java files with main classes in
        sourceSets.main.allJava.each {
            if(it.text.contains("public static void main")) {
                def pkg = relativePath(it) - 'src/main/java/' - '.java'
                pkg = pkg.tr "/", "."
                  println "${mainClasses.size()}. $pkg"
                mainClasses << pkg
            }
        }
          // Now prompt the user to choose a main class to use
        while(selection == null) {
            def input = System.console().readLine "#? "
              if(input?.isInteger()) {
                selection = input as int
                  if(selection >= 0 && selection < mainClasses.size()) {
                    break
                } else {
                    selection = null
                }
            } else if(input?.toLowerCase() == "quit") {
                return
            }
              if(selection == null) {
                println "Unknown option."
            }
        }
          main = mainClasses[selection]
        classpath = sourceSets.main.runtimeClasspath
    }
}

My confusion is because: If I don’t include the code in a ‘doFirst’ or ‘doLast’ closure the user is prompted for input during the configuration phase, I now understand that I need to put it in ‘doFirst’ or ‘doLast’ so that is only executed during the execution phase.

However the user will only be prompted for input if I use ‘doFirst’? If I use the ‘doLast’ closure then the user isn’t prompted, it just goes right through and complains that no main class was selected.

doFirst and doLast add actions to your task.

Because your task is a JavaExec task it already has an action to execute a main class.

doFirst adds your task to prompt the user before this pre-existing action.

doLast adds it after (when it is too late).

Ahhh, of course. it’s all so obvious!