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