Executing task in beforeEvaluate from settings.gradle

I’m working through my deprecations with 4.10 in preparation for the 5.0 upgrade. I’m struggling right now to find a replacement for a TaskInternal.execute() method.

We have our feature toggle code defined in settings.gradle inside a beforeEvaluate. Here’s the relevant bits (with comments):

/* After the initialization phase is completed and projects have been loaded, we will
 * generate the files needed to toggle features at build time. To ensure this is the
 * very first action executed we run the following before the projects are evaluated
 * (the configuration phase). By doing this, the properties needed are loaded so we can toggle
 * features during the configuration and execution phases of the gradle build.
 */

gradle.rootProject {
	beforeEvaluate { project ->

		File featuresConfFile = ...
		File txtFile = ...
		File javaFile = ...
	
		//closure which execute perl parser to generate java file with constants needed for compile and run-time toggling
		def execParserForSource = {
			exec {
				commandLine ...
			}
		}

		/* generateFeaturesDef creates the necessary files for feature toggle at
		 * build, compile and run-time. We want this to be the first thing configured
		 * so we can load the properties which are used to toggle at build time for
		 * all subprojects.
		 */
		task generateFeaturesDef {
			inputs.file featuresConfFile
			outputs.files txtFile, javaFile

			doFirst {
				//exec perl parser to generate the necessary files for feature toggle
				execParserForSource()
			}
		}

		//explicitly execute generateFeaturesDef before build continues on to subprojects
		project.tasks.generateFeaturesDef.execute()
	}
}

I haven’t been able to come up with any other way to execute this task. Any suggestions on how I can replicate this behavior in 5.0?

Thanks!

Hi Brian,

why are you using a task to execute that code? Why don’t you just call execParserForSource directly? I.e.:

//closure which execute perl parser to generate java file with constants needed for compile and run-time toggling

    beforeEvaluate {
		def execParserForSource = {
			exec {
				commandLine ...
			}
		}

		/* generateFeaturesDef creates the necessary files for feature toggle at
		 * build, compile and run-time. We want this to be the first thing configured
		 * so we can load the properties which are used to toggle at build time for
		 * all subprojects.
		 */
         execParserForSource()
    }

I am also pretty sure you can wrap the code generation in a task and then have the tasks which consume this code (compilation) depend on it.

Cheers,
Stefan

I believe the primary reason it was done with a task was to make use of the inputs to prevent the closure from being executed if the source file hadn’t changed.

Is there a way to replicate that inputs logic in a closure?

If you want to participate in up-to-date checking, I think it makes much more sense to create a task, on which all the tasks that depend on the generated files depend on.

Why do you need the generated files at configuration time?

The execParserForSource closure generates a properties file with a bunch of different flags in it that we then load into a ext variable. Then sub-projects can look for those flags to decide whether to build a given project or not. Something like this:

sub-project.gradle:

task featureSample(type: Jar) {
    archiveName ...
    inputs ...
    outputs ...
}
featureSample.onlyIf { featuretoggle_properties."FEATURE1" }

Here’s another example:

// Don't do feature1 component tests if not enabled
if (!featuretoggle_properties."FEATURE1") {
    sourceSets {
        componentTest {
            java {
                exclude ...
            }
        }
    }
}