Currently, we rebuild the buildsystem of our enterprise software to use Gradle 3.2.1+ and Buildship 2.0.0+. We want to use the composite-build for simplifying the developer’s life. But we have unexpected jar-task executions of the included builds, when we import our projects with Buildship.
I reduced our multi-project structure for reproducing the problem for both approaches that we tried:
https://github.com/pwoelfle/gradle-composite-build
Approach one
The project-lib
is used as included-build in project-application
. I import project-lib
into a new workspace with Buildship and then I also import project-application
. Everything looks as expected, but when I check project-lib
, I saw that the jar of this project was created. My expectation was that the binary dependency to project-lib
in project-application
is simply substituted as project dependency without building the project-lib
.
With the current behaviour the workspace setup would have the duration of the build-time of each included-build. This is irrelevant in small projects, because the jar is created quickly. But in our case the built-time for the library project is about 2 minutes. And some more of our projects use bigger projects with build-times about 12 minutes.
Moreover after importing all projects (which forces the :jar
execution of all included-builds), the whole workspace must be build with Eclipse again. This doubled the duration until a developer can start working.
I debugged the import and found out that the method org.gradle.plugins.ide.internal.IdeDependenciesExtractor#resolvedExternalDependencies
forces the :jar
task execution, because the dependency is resolved as external dependency.
Stacktrace
java.lang.Thread.State: RUNNABLE
at org.gradle.composite.internal.IncludedBuildArtifactBuilder.execute(IncludedBuildArtifactBuilder.java:58)
at org.gradle.composite.internal.IncludedBuildArtifactBuilder.build(IncludedBuildArtifactBuilder.java:52)
at org.gradle.composite.internal.CompositeProjectArtifactBuilder.build(CompositeProjectArtifactBuilder.java:39)
at org.gradle.api.internal.artifacts.ivyservice.projectmodule.AggregatingProjectArtifactBuilder.build(AggregatingProjectArtifactBuilder.java:33)
at org.gradle.api.internal.artifacts.ivyservice.projectmodule.CacheLockReleasingProjectArtifactBuilder$1.run(CacheLockReleasingProjectArtifactBuilder.java:36)
at org.gradle.internal.Factories$1.create(Factories.java:25)
at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:239)
at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:310)
at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunningOperation(DefaultPersistentDirectoryStore.java:137)
at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingCache.longRunningOperation(DefaultCacheFactory.java:183)
at org.gradle.api.internal.artifacts.ivyservice.DefaultCacheLockingManager.longRunningOperation(DefaultCacheLockingManager.java:48)
at org.gradle.api.internal.artifacts.ivyservice.projectmodule.CacheLockReleasingProjectArtifactBuilder.build(CacheLockReleasingProjectArtifactBuilder.java:33)
at org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectDependencyResolver.resolveArtifact(ProjectDependencyResolver.java:105)
at org.gradle.api.internal.artifacts.ivyservice.resolveengine.ComponentResolversChain$ArtifactResolverChain.resolveArtifact(ComponentResolversChain.java:103)
at org.gradle.api.internal.artifacts.ivyservice.CacheLockingArtifactResolver$3.run(CacheLockingArtifactResolver.java:61)
at org.gradle.internal.Factories$1.create(Factories.java:25)
at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:179)
at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:162)
at org.gradle.cache.internal.DefaultPersistentDirectoryStore.useCache(DefaultPersistentDirectoryStore.java:129)
at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingCache.useCache(DefaultCacheFactory.java:191)
at org.gradle.api.internal.artifacts.ivyservice.DefaultCacheLockingManager.useCache(DefaultCacheLockingManager.java:56)
at org.gradle.api.internal.artifacts.ivyservice.CacheLockingArtifactResolver.resolveArtifact(CacheLockingArtifactResolver.java:59)
at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingArtifactResolver.resolveArtifact(ErrorHandlingArtifactResolver.java:56)
at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DefaultArtifactSet$LazyArtifactSource.create(DefaultArtifactSet.java:93)
at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DefaultArtifactSet$LazyArtifactSource.create(DefaultArtifactSet.java:80)
at org.gradle.api.internal.artifacts.DefaultResolvedArtifact.getFile(DefaultResolvedArtifact.java:90)
at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$1$1.isSatisfiedBy(DefaultLenientConfiguration.java:136)
at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$1$1.isSatisfiedBy(DefaultLenientConfiguration.java:133)
at org.gradle.util.CollectionUtils.filter(CollectionUtils.java:137)
at org.gradle.util.CollectionUtils.filter(CollectionUtils.java:105)
at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$1.create(DefaultLenientConfiguration.java:133)
at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$1.create(DefaultLenientConfiguration.java:131)
at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:179)
at org.gradle.cache.internal.DefaultPersistentDirectoryStore.useCache(DefaultPersistentDirectoryStore.java:125)
at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingCache.useCache(DefaultCacheFactory.java:187)
at org.gradle.api.internal.artifacts.ivyservice.DefaultCacheLockingManager.useCache(DefaultCacheLockingManager.java:52)
at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration.getArtifacts(DefaultLenientConfiguration.java:131)
at org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingConfigurationResolver$ErrorHandlingLenientConfiguration.getArtifacts(ErrorHandlingConfigurationResolver.java:84)
at org.gradle.plugins.ide.internal.resolver.DefaultIdeDependencyResolver.getExternalArtifacts(DefaultIdeDependencyResolver.java:237)
at org.gradle.plugins.ide.internal.resolver.DefaultIdeDependencyResolver.getIdeRepoFileDependencies(DefaultIdeDependencyResolver.java:132)
at org.gradle.plugins.ide.internal.IdeDependenciesExtractor.resolvedExternalDependencies(IdeDependenciesExtractor.java:181)
at org.gradle.plugins.ide.internal.IdeDependenciesExtractor.extractRepoFileDependencies(IdeDependenciesExtractor.java:77)
at org.gradle.plugins.ide.eclipse.model.internal.EclipseDependenciesCreator.createLibraryDependencies(EclipseDependenciesCreator.java:82)
at org.gradle.plugins.ide.eclipse.model.internal.EclipseDependenciesCreator.createDependencyEntries(EclipseDependenciesCreator.java:58)
at org.gradle.plugins.ide.eclipse.model.internal.ClasspathFactory.createDependencies(ClasspathFactory.java:69)
at org.gradle.plugins.ide.eclipse.model.internal.ClasspathFactory.createEntries(ClasspathFactory.java:46)
at org.gradle.plugins.ide.eclipse.model.EclipseClasspath.resolveDependencies(EclipseClasspath.java:304)
at org.gradle.plugins.ide.eclipse.model.EclipseClasspath.mergeXmlClasspath(EclipseClasspath.java:311)
at org.gradle.plugins.ide.eclipse.GenerateEclipseClasspath.configure(GenerateEclipseClasspath.java:43)
at org.gradle.plugins.ide.eclipse.GenerateEclipseClasspath.configure(GenerateEclipseClasspath.java:28)
at org.gradle.plugins.ide.api.XmlGeneratorTask$1.configure(XmlGeneratorTask.java:40)
at org.gradle.plugins.ide.api.XmlGeneratorTask$1.configure(XmlGeneratorTask.java:32)
at org.gradle.plugins.ide.api.GeneratorTask.generate(GeneratorTask.java:81)
at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
Is this the expected behavior? In my opinion, dependencies that could be satisfied by an included build as project dependency, could be directly declared as project dependency. As well because the dependency is only used for creating the .classpath
file.
#Approach two
The composite-build
project uses the project-lib
and project-application
as included builds. I import composite-build
into a new workspace with Buildship and then both included-build projects.
This time no :jar
task is executed, but there is also no substitution of the included build dependency that could be satisfied by a project dependency.
Thanks for your help, you doing a great job