How can I match all build scripts?

I want to run CodeNarc over the actual Gradle build scripts. But how do I determine which files are actually involved in the build?

I couldn’t find a way, so my workaround was going to be this:

tasks.register('codenarcGradle', CodeNarc) {
  source project.projectDir
  include '**/*.gradle'
  exclude '**/build/**'
  exclude '**/src/**'
  exclude '**/test-data/**'
}

But it seems like the exclude rules don’t actually work, because I see it crawling far deeper than some directories which should have matched the rule:

[ant:codenarc] skipping symbolic link /Users/tester/Documents/acme/core/master/release/macos/desktop/build/Acme/Applications/Unity/MonoDevelop.app/Contents/Frameworks/Mono.framework/Versions/Current/Current/Current/Current/Current/Current -- too many levels of symbolic links.
[ant:codenarc] skipping symbolic link /Users/tester/Documents/acme/core/master/release/macos/desktop/build/Acme/Applications/Adium.app/Contents/Frameworks/libjson-glib.framework/Versions/1.0.0/Headers/json-glib/json-glib/json-glib/json-glib/json-glib/json-glib -- too many levels of symbolic links.

It seems really questionable for it to be following symlinks in the first place, but I’d hoped that filtering out build directories would at least stop it walking these directories. Sadly, it doesn’t.

Back to the actual thing I want to do though, is there no way to get a list of all build scripts which were loaded as part of the build? Searching the whole file tree is slow anyway, and it seems like Gradle should already have this information available somewhere.

Hi,

I think you are looking for Project.getBuildFile:

tasks.register('...', CodeNarc) {
    include(allprojects.collect { Project p -> p.buildFile.absolutePath })
}

I have not tried it with CodeNarc, but it should work:

settings.gradle:

include "foo"
include "bar"
project(":foo").buildFileName = "foo.gradle"

build.gradle:

tasks.register('describe') {
	doLast {
		println allprojects.collect { Project p -> p.buildFile }
	}
}
me@laptop:/tmp/foobar$ gradle describe

> Task :describe
[/tmp/foobar/build.gradle, /tmp/foobar/bar/build.gradle, /tmp/foobar/foo/foo.gradle]

I have tried buildFile, but it only returns the one build script for the project you call it on. However, projects can include other build scripts, like this:

apply from: 'gradle/common-stuff.gradle'

I’d like to apply the same checks to common-stuff.gradle too.

The Gradle model only cares about the project buildFile because that’s the entry point for configuring the project. When apply from: is encountered in the build file, it loads the referenced file, creates a child classloader, and then executes the code as a script plugin in that child classloader on the fly. There’s not really a reason for the Gradle model to care about this detail outside of the apply.

The ScriptHandler of the child script themselves know they were loaded though, so I imagine you could do some meta programming to have the ScriptHandler register themselves to the owning project.

Ah, so one option here is that I make myself a custom Groovy context to evaluate the build script, and use that to intercept attempts to apply things to the project.

Although I’d have to be very careful not to let people come up with other sneaky ways of applying stuff, so maybe it’s easier to just try to write a good enough glob to match files ending with .gradle and just suffer the performance hit.