Adam Murdoch wrote:


Steve Appling wrote:
While updating our build to include the latest changes in the trunk, I ran into some issues related to the removal of unmanagedClasspath. I finally got our build working, but I'm not sure I like the direction.

We chose to store some non-unit tests in different directories under src, so we have src/main, src/test, src/test-functional. We have a set of functional test tasks similar to the unit test ones: processFunctionalTestResources, compileFunctionalTests, and functionalTest.

Each of these tasks previously used the unmanagedClasspath property to add the appropriate classes directory similar to what is done by the JavaPlugin for the unit test tasks. For example, the compileFunctionalTests task added the unit test output directory by using: unmanagedClasspath = compileTests.unmanagedClasspath + project.convention.testClassesDir

I followed the example in the current JavaPlugin and ended up with something like this in my new gradle file:

   dependencies.add('functionalTestCompile', [
      getDisplayName: { "Anonymous File Collection" },
getFiles : { Collections.singleton(project.convention.testClassesDir)}
   ] as AbstractFileCollection)


You can use the Project.files() method:

dependencies.add('functionalTestCompile', files {project.convention.testClassesDir})

You don't necessarily need to use a configuration for this, either (you did in earlier versions of Gradle). This would work:

compileFunctionalTests.classpath = files(configurations.testCompile, project.convention.testClassesDir)


This is exactly what I needed in this case - thanks.


I didn't like having the internal interface AbstractFileCollection in my gradle file, so I added support for Files to the SelfResolvingDependencyFactory so that you could just use: dependencies.add('functionalTestCompile', project.convention.testClassesDir)

I'll be glad to post a patch for this if anyone thinks this would be useful.


Do we need this, given you can use the files() method?
Nope, the files method is fine.


I still don't like this solution, however. I may just not understand how this was intended to work in 0.7. The distinctions between the SelfResolvingDependency and other types of Dependencies are way too subtle for me. It is not obvious that passing certain types of objects to dependencies.add results in "unmanaged" additions to the classpath. I would like the "unmanaged" aspect of this to be much more explicit. This seems to me like a different type of path on a configuration, not a different type of dependency - it doesn't impact the DAG.

It will, for generated files. For example, adding the classes dir into a configuration will add the compile task into the dependencies of any task using the configuration.

This step is the very start of the teasing apart of the ivy dependency model into a richer model. I think dependencies have several independent aspects, which you should be able to control for a given dependency:

1. Where do it's artifacts come from? Previously, we had one possible source: they are located in a repository somewhere. Now we have two sources: you can use a repository, or you can explicitly specify the files. We can now add more: eg the from the current Gradle instance.

2. Where can an external project find the dependency? That is, what meta-info should be included in the project descriptor when it is published, if any?

3. How are the artifacts produced? That is, which tasks should be executed in order to produce the artifacts for the dependency?

I think you should be able to declare any combination of these for a given dependency. Right now, we have a small, hard-coded set of combinations:

- file: the artifacts are explicit, they are not visible to an external project, and they are not built

- module: find the artifacts in a repository, external projects find them in a repository, and they are not built.

- project: find the artifacts in a repository, external projects find them in a repository, and they are built by the appropriate tasks in the target project.

Some other useful, and missing, variations:

- The dependency is available locally, but uses some naming scheme which doesn't work with flatDir. You should be able to specify the artifacts explicitly, but also include the dependency in the published descriptor, so that external projects use the dependency out of a repository.

- Your project uses a directory which is also published as an archive, such as classes dir. You should be able to declare a dependency which uses the directory within the project, and the published archive in external projects. If you use the dependency, the appropriate tasks are executed to build the contents of the directory.

- You use a dependency which is built by an external project on the local machine. You should be able to declare a dependency which uses the artifacts built by that external project, and also knows how to run a build for that external project.

- Gradle API or Groovy or Ant. Gradle should be able to give you a dependency which uses the appropriate jars out of the current Gradle distribution, or out of a given Groovy or Ant distribution, and also includes the dependency in the published descriptor.

To me, this process is about allowing the dependency model to scale down in complexity to simple cases, and up in complexity to cases we haven't thought of yet. We plan to do this by allowing the different aspects of a dependency to be composed into whichever combination you like, rather than providing fixed combination. This scales down, because you can ignore the aspects you don't care about, and it scales up, because you can control each and every aspect of any dependency.

At its most basic, a configuration is just a named set of files. It makes perfect sense, I think, to be able to add a collection of files directly to a configuration, if I don't want or need to provide any meta-info about those files, or use any repositories, or publish the configuration.

Digging a bit deeper, a configuration is made up of a set of dependencies, each of which resolves to a set of files and has some meta-info associated with it. So it also makes sense to me that, when I do add a collection of files to a configuration, the collection is added as a dependency. This means I can, if I want, specify some or all of the meta-info about those files: here's some files to use, and if an external project needs them, they're also known to the world as groovy-all version 1.6.2, and if I need to use them, they are built by the 'downloadGroovy' task.


Adam

I like the flexibility that you are suggesting and would love to see some of
these changes.

I am still having some problems related (I think) to the unmanagedClasspath changes. I can't get our buildSrc to work now.
Previously we had to do the following in the buildSrc/build.gradle:
  compile.groovyClasspath = org.gradle.util.BootstrapUtil.groovyFiles
  testCompile.groovyClasspath = org.gradle.util.BootstrapUtil.groovyFiles
compile.unmanagedClasspath(org.gradle.util.BootstrapUtil.gradleClasspath as File[])

I have tried several combinations to get this working, but still can't get the gradle files on the classpath in buildsrc. I get errors like "unable to resolve class org.gradle.api.Project".

I am currently just trying to add the gradle files to the compile classpath 
using:
dependencies {
   compile files(org.gradle.util.BootstrapUtil.gradleClasspath)
}

This still doesn't work - I would appreciate any other ideas to try. Perhaps this will make more sense on Monday :)


--
Steve Appling
Automated Logic Research Team


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email


Reply via email to